-
Notifications
You must be signed in to change notification settings - Fork 138
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
CBG-3700 fix race conditions #6633
Conversation
- each ServerContext will reset the global logger. Provide a way to avoid the logging setup, assuming that the test logging framework will already be configured. The logger can get reset while a different server (database) is logging, such as writing checkpoint documents. - dbReplicatorStats map can be accessed simultaneously by SGReplicateMgr and when it is explicitly called in the test.
rest/config_startup.go
Outdated
@@ -85,6 +85,8 @@ type StartupConfig struct { | |||
CouchbaseKeepaliveInterval *int `json:"couchbase_keepalive_interval,omitempty" help:"TCP keep-alive interval between SG and Couchbase server"` | |||
|
|||
DeprecatedConfig *DeprecatedConfig `json:"-,omitempty" help:"Deprecated options that can be set from a legacy config upgrade, but cannot be set from a 3.0 config."` | |||
|
|||
avoidLoggingSetup bool `json:"-"` // Used to avoid logging setup so as to not modify globals. This only used for testing multiple ServerContexts simultaneously. This will use the same logging configuration as is already set up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we could build this into initLogging, so that callers don't need to worry about setting this flag? (i.e. have InitLogging run within a mutex and set a global flag when complete, and check that flag when run)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a single test TestConfigsIncludeDefaults
that requires initialization of a logger, to test whether it will pass the DCP
base key to the database level. I'm not convinced this part of this test needs the workaround defer RunBootstrapLoggerInitialization(t)()
.
I don't know if I like this solution better because it relies on a global but I think it makes the part of the code to be modified very small, which I like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the previous commit, I had the impression that we should only ever be calling SetupAndValidateLogging once per process. (and that unit tests with multiple server contexts should reuse the same logging config). Is that accurate? If yes, I think we should be encapsulate the 'run once' logic inside SetupAndValidateLogging.
I looked at TestConfigsIncludeDefaults and I think it can just use SetUpTestLogging to initialize the DCP log key - I don't think it needs a custom call to SetupAndValidateLogging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed to add config.Logging.Console.Enabled = base.BoolPtr(true)
to this test, which is normally enabled as a side effect of InitLogging
but not normally needed in a JSON for server config. I think this is fine for this test, which keeps the guts of the inheritance.
…only need for a single test
Co-authored-by: Adam Fraser <[email protected]>
This causes a race condition in the instance that two databases with the same config group are created simultaneously. An example of how this can happen is: - config polling to pick up a db config A - GET /dbA/ The second will independently attempt to load the configuration while the first is running. In theory, this could happen for any different database in step 2, since all databases will be in the same group id.
rest/config.go
Outdated
log.Printf("[ERR] Error setting up logging: %v", err) | ||
return nil, fmt.Errorf("error setting up logging: %v", err) | ||
// logger will be initialized only when running tests | ||
if !loggerInitialized { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't feel like quite the right place to be using this variable - wouldn't we'd want to encapsulate it in the logging handling (inside SetupAndValidateLogging)?
We'd also still need some sort of synchronization to avoid races.
rest/config_startup.go
Outdated
@@ -85,6 +85,8 @@ type StartupConfig struct { | |||
CouchbaseKeepaliveInterval *int `json:"couchbase_keepalive_interval,omitempty" help:"TCP keep-alive interval between SG and Couchbase server"` | |||
|
|||
DeprecatedConfig *DeprecatedConfig `json:"-,omitempty" help:"Deprecated options that can be set from a legacy config upgrade, but cannot be set from a 3.0 config."` | |||
|
|||
avoidLoggingSetup bool `json:"-"` // Used to avoid logging setup so as to not modify globals. This only used for testing multiple ServerContexts simultaneously. This will use the same logging configuration as is already set up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the previous commit, I had the impression that we should only ever be calling SetupAndValidateLogging once per process. (and that unit tests with multiple server contexts should reuse the same logging config). Is that accurate? If yes, I think we should be encapsulate the 'run once' logic inside SetupAndValidateLogging.
I looked at TestConfigsIncludeDefaults and I think it can just use SetUpTestLogging to initialize the DCP log key - I don't think it needs a custom call to SetupAndValidateLogging.
// If SetupServerContext is called while any other go routines that might use logging are running, it will | ||
// cause a data race, therefore only initialize logging and other globals on the first call. From a main | ||
// program, there is only one ServerContext. | ||
if serverContextGlobalsInitialized.CompareAndSwap(false, true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how this is intended to work for a suite of tests that only invoke SetupServerContext
once per test.
Is it expected that only the first test gets to set global config, and all others can't?
I'd have expected this flag to be reset between tests maybe (t.Cleanup
?), if the intention is to only allow this to be run once per test to avoid races
// If SetupServerContext is called while any other go routines that might use logging are running, it will | ||
// cause a data race, therefore only initialize logging and other globals on the first call. From a main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't protect against tests that have a mix of RestTester and full Bootstrap/ServerContext (e.g. TestGroupIDReplications
)
- each ServerContext will reset the global logger. Only reset the global logging once per execution of the program, to simulate what happens in mane. - dbReplicatorStats map can be accessed simultaneously by SGReplicateMgr and when it is explicitly called in the test. - Mutex RegisterImportPindexImpl which was unsynchronized when multiple calls to NewDatabaseContext happen simultaneously.
Addresses a race in
go test -tags cb_sg_enterprise ./rest/replicatortest -race -run TestGroupIDReplications
I don't really care for the way I avoid re-initialization of the global logger, but I don't have a better alternative in mind.
Pre-review checklist
fmt.Print
,log.Print
, ...)base.UD(docID)
,base.MD(dbName)
)docs/api
Integration Tests
GSI=true,xattrs=true
https://jenkins.sgwdev.com/job/SyncGateway-Integration/2450/