Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit to single inflight package syncing operation #289

Merged
merged 12 commits into from
Aug 29, 2024

Conversation

tpaschalis
Copy link
Member

This PR revives work done in previous PRs (#118, #120) to make sure that only a single package syncing operation is ever in flight and also adds a test.

The previous PRs did not account for needing to also protect initStatuses and SetPackageStatuses, so that's why the Lock and Unlock statements are not just paired in doSync. If you think the intent would be clearer using a sync.WaitGroup, let me know.

The new test makes sure that the mutex correctly protects the local storage; if we comment out the calls to Lock/Unlock and run the test with the -race flag we can see the race condition taking place

# Without using the mutex we can see the race condition of messages sent in parallel
$ go test -run=TestPackageUpdatesInParallel -v -race -count=1
=== RUN   TestPackageUpdatesInParallel
==================
WARNING: DATA RACE
Write at 0x00c00003cdb0 by goroutine 10:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).SetLastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:95 +0x34
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).reportStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:335 +0x78
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).syncPackage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:199 +0x4dc
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:132 +0x3b0
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Previous read at 0x00c00003cdb0 by goroutine 8:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).LastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:91 +0x30
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).initStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:88 +0x64
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:59 +0x78
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func2()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:197 +0x4d0

Goroutine 10 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func3()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:216 +0x4d0

Goroutine 8 (finished) created at:
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:196 +0x4b0
  testing.tRunner()
      /opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1689 +0x180
  testing.(*T).Run.gowrap1()
      /opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1742 +0x40
==================
==================
WARNING: DATA RACE
Write at 0x00c0000999e0 by goroutine 11:
  runtime.mapaccess2_faststr()
      /opt/homebrew/Cellar/go/1.22.2/libexec/src/runtime/map_faststr.go:108 +0x42c
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).CreatePackage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:50 +0x74
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).syncPackage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:203 +0x528
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:132 +0x3b0
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Previous read at 0x00c0000999e0 by goroutine 10:
  runtime.mapdelete()
      /opt/homebrew/Cellar/go/1.22.2/libexec/src/runtime/map.go:696 +0x43c
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).Packages()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:36 +0x64
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).deleteUnneededLocalPackages()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:303 +0x58
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:125 +0x1b4
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Goroutine 11 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func2()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:197 +0x4d0

Goroutine 10 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func3()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:216 +0x4d0
==================
==================
WARNING: DATA RACE
Write at 0x00c00003cdb0 by goroutine 11:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).SetLastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:95 +0x34
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).reportStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:335 +0x78
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).syncPackage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:229 +0x780
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:132 +0x3b0
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Previous write at 0x00c00003cdb0 by goroutine 10:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).SetLastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:95 +0x34
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).reportStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:335 +0x78
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).syncPackage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:229 +0x780
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:132 +0x3b0
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Goroutine 11 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func2()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:197 +0x4d0

Goroutine 10 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func3()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:216 +0x4d0
==================
==================
WARNING: DATA RACE
Write at 0x00c00003cdb0 by goroutine 10:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).SetLastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:95 +0x34
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).reportStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:335 +0x78
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:151 +0x69c
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Previous write at 0x00c00003cdb0 by goroutine 11:
  github.com/open-telemetry/opamp-go/client/internal.(*InMemPackagesStore).SetLastReportedStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/inmempackagestore.go:95 +0x34
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).reportStatuses()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:335 +0x78
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).doSync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:151 +0x69c
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync.gowrap1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x4c

Goroutine 10 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func3()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:216 +0x4d0

Goroutine 11 (running) created at:
  github.com/open-telemetry/opamp-go/client/internal.(*packagesSyncer).Sync()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/packagessyncer.go:69 +0x15c
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func1()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:185 +0x68
  github.com/open-telemetry/opamp-go/client/types.CallbacksStruct.OnMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/types/callbacks.go:161 +0x84
  github.com/open-telemetry/opamp-go/client/types.(*CallbacksStruct).OnMessage()
      <autogenerated>:1 +0x20
  github.com/open-telemetry/opamp-go/client/internal.(*receivedProcessor).ProcessReceivedMessage()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/receivedprocessor.go:160 +0xe94
  github.com/open-telemetry/opamp-go/client/internal.TestPackageUpdatesInParallel.func2()
      /Users/tpaschalis/GitRepos/opamp-go/client/internal/httpsender_test.go:197 +0x4d0
==================
    testing.go:1398: race detected during execution of test
--- FAIL: TestPackageUpdatesInParallel (0.10s)
FAIL
exit status 1
FAIL	github.com/open-telemetry/opamp-go/client/internal	0.286s

Fixes #84

@tpaschalis tpaschalis requested a review from a team June 25, 2024 19:51
Copy link

codecov bot commented Jun 25, 2024

Codecov Report

Attention: Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.

Project coverage is 76.89%. Comparing base (ed38d5f) to head (d016331).
Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
client/internal/packagessyncer.go 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #289      +/-   ##
==========================================
+ Coverage   76.32%   76.89%   +0.56%     
==========================================
  Files          25       25              
  Lines        1681     1692      +11     
==========================================
+ Hits         1283     1301      +18     
+ Misses        291      285       -6     
+ Partials      107      106       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@tpaschalis tpaschalis force-pushed the single-package-syncing branch from 88b2071 to 8fec037 Compare June 30, 2024 16:29
@tpaschalis
Copy link
Member Author

I've rebased main and fixed the conflict from a recent PR, let me know what you think! 🙌

Signed-off-by: Paschalis Tsilias <[email protected]>
@tpaschalis tpaschalis requested a review from srikanthccv July 2, 2024 15:38
Copy link
Member

@srikanthccv srikanthccv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor comments, mostly LGTM.

client/internal/packagessyncer.go Outdated Show resolved Hide resolved
client/internal/wsreceiver_test.go Show resolved Hide resolved
Signed-off-by: Paschalis Tsilias <[email protected]>
Signed-off-by: Paschalis Tsilias <[email protected]>
@tpaschalis tpaschalis requested a review from srikanthccv July 5, 2024 14:30
Copy link
Member

@srikanthccv srikanthccv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

},
}

// Set the RequestInstanceUid flag on the tracked state to request the server for a new ID to use.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong comment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch, removing it.

client/internal/httpsender_test.go Outdated Show resolved Hide resolved
Signed-off-by: Paschalis Tsilias <[email protected]>
Copy link
Member

@tigrannajaryan tigrannajaryan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I was out last week.

client/internal/httpsender_test.go Show resolved Hide resolved
client/internal/httpsender_test.go Outdated Show resolved Hide resolved
client/internal/httpsender_test.go Outdated Show resolved Hide resolved
client/internal/httpsender_test.go Outdated Show resolved Hide resolved
Signed-off-by: Paschalis Tsilias <[email protected]>
Signed-off-by: Paschalis Tsilias <[email protected]>
Comment on lines +287 to +298
// Make sure that both Sync calls have gone through _before_ releasing the first one.
// This means that they're both called in parallel, and that the race
// detector would always report a race condition, but proper locking makes
// sure that's not the case.
assert.Eventually(t, func() bool {
return messages.Load() == 2
}, 2*time.Second, 100*time.Millisecond, "both messages must have been processed successfully")

// Release the second Sync call so it can continue and wait for both of them to complete.
blockSyncCh <- struct{}{}
<-doneCh[0]
<-doneCh[1]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense now. Thanks!

@tigrannajaryan tigrannajaryan merged commit 536037b into open-telemetry:main Aug 29, 2024
7 checks passed
@tigrannajaryan
Copy link
Member

Thanks for your patience @tpaschalis

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make sure only one package syncing operation happens at a time
3 participants