From 48fbd3ff07d9b8fb00673909fd519d0719b629a6 Mon Sep 17 00:00:00 2001 From: Ben Ash Date: Thu, 14 Oct 2021 13:29:09 -0400 Subject: [PATCH] Rename PreventStaleReads to ReadYourWrites - replace doc references to stale reads with read-after-write --- api/client.go | 58 ++++++++++++++++++++++----------------------- api/client_test.go | 11 +++++---- changelog/12814.txt | 2 +- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/api/client.go b/api/client.go index c312cff163ce9..2d1c3b683f43e 100644 --- a/api/client.go +++ b/api/client.go @@ -139,14 +139,14 @@ type Config struct { // its clone. CloneHeaders bool - // PreventStaleReads enables the Client to require discovered cluster - // replication states for each request. + // ReadYourWrites ensures isolated read-after-write semantics by + // providing discovered cluster replication states in each request. // The shared state is automatically propagated to all Client clones. // // Note: Careful consideration should be made prior to enabling this setting // since there will be a performance penalty paid upon each request. // This feature requires Enterprise server-side. - PreventStaleReads bool + ReadYourWrites bool } // TLSConfig contains the parameters needed to configure TLS on the HTTP client @@ -511,7 +511,7 @@ func NewClient(c *Config) (*Client, error) { headers: make(http.Header), } - if c.PreventStaleReads { + if c.ReadYourWrites { client.replicationStateStore = &replicationStateStore{} } @@ -547,7 +547,7 @@ func (c *Client) CloneConfig() *Config { newConfig.OutputCurlString = c.config.OutputCurlString newConfig.SRVLookup = c.config.SRVLookup newConfig.CloneHeaders = c.config.CloneHeaders - newConfig.PreventStaleReads = c.config.PreventStaleReads + newConfig.ReadYourWrites = c.config.ReadYourWrites // we specifically want a _copy_ of the client here, not a pointer to the original one newClient := *c.config.HttpClient @@ -873,8 +873,8 @@ func (c *Client) CloneHeaders() bool { return c.config.CloneHeaders } -// SetPreventStaleReads to prevent reading stale cluster replication state. -func (c *Client) SetPreventStaleReads(preventStaleReads bool) { +// SetReadYourWrites to prevent reading stale cluster replication state. +func (c *Client) SetReadYourWrites(preventStaleReads bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() @@ -886,17 +886,17 @@ func (c *Client) SetPreventStaleReads(preventStaleReads bool) { c.replicationStateStore = nil } - c.config.PreventStaleReads = preventStaleReads + c.config.ReadYourWrites = preventStaleReads } -// PreventStaleReads gets the configured value of PreventStaleReads -func (c *Client) PreventStaleReads() bool { +// ReadYourWrites gets the configured value of ReadYourWrites +func (c *Client) ReadYourWrites() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() - return c.config.PreventStaleReads + return c.config.ReadYourWrites } // Clone creates a new client with the same configuration. Note that the same @@ -916,21 +916,21 @@ func (c *Client) Clone() (*Client, error) { defer config.modifyLock.RUnlock() newConfig := &Config{ - Address: config.Address, - HttpClient: config.HttpClient, - MinRetryWait: config.MinRetryWait, - MaxRetryWait: config.MaxRetryWait, - MaxRetries: config.MaxRetries, - Timeout: config.Timeout, - Backoff: config.Backoff, - CheckRetry: config.CheckRetry, - Logger: config.Logger, - Limiter: config.Limiter, - OutputCurlString: config.OutputCurlString, - AgentAddress: config.AgentAddress, - SRVLookup: config.SRVLookup, - CloneHeaders: config.CloneHeaders, - PreventStaleReads: config.PreventStaleReads, + Address: config.Address, + HttpClient: config.HttpClient, + MinRetryWait: config.MinRetryWait, + MaxRetryWait: config.MaxRetryWait, + MaxRetries: config.MaxRetries, + Timeout: config.Timeout, + Backoff: config.Backoff, + CheckRetry: config.CheckRetry, + Logger: config.Logger, + Limiter: config.Limiter, + OutputCurlString: config.OutputCurlString, + AgentAddress: config.AgentAddress, + SRVLookup: config.SRVLookup, + CloneHeaders: config.CloneHeaders, + ReadYourWrites: config.ReadYourWrites, } client, err := NewClient(newConfig) if err != nil { @@ -1048,7 +1048,7 @@ func (c *Client) RawRequestWithContext(ctx context.Context, r *Request) (*Respon cb(r) } - if c.config.PreventStaleReads { + if c.config.ReadYourWrites { c.replicationStateStore.requireState(r) } @@ -1163,7 +1163,7 @@ START: cb(result) } - if c.config.PreventStaleReads { + if c.config.ReadYourWrites { c.replicationStateStore.recordState(result) } } @@ -1357,7 +1357,7 @@ func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo } // replicationStateStore is used to track cluster replication states -// in order to prevent stale reads. +// in order to ensure proper read-after-write semantics for a Client. type replicationStateStore struct { m sync.RWMutex store []string diff --git a/api/client_test.go b/api/client_test.go index b5111c677760d..f335a765b3ed3 100644 --- a/api/client_test.go +++ b/api/client_test.go @@ -438,7 +438,7 @@ func TestClone(t *testing.T) { { name: "preventStaleReads", config: &Config{ - PreventStaleReads: true, + ReadYourWrites: true, }, }, } @@ -520,11 +520,12 @@ func TestClone(t *testing.T) { } } } - if tt.config.PreventStaleReads && client1.replicationStateStore == nil { + if tt.config.ReadYourWrites && client1.replicationStateStore == nil { t.Fatalf("replicationStateStore is nil") } if !reflect.DeepEqual(client1.replicationStateStore, client2.replicationStateStore) { - t.Fatalf("expected replicationStateStore %v, actual %v", client1.replicationStateStore, client2.replicationStateStore) + t.Fatalf("expected replicationStateStore %v, actual %v", client1.replicationStateStore, + client2.replicationStateStore) } }) } @@ -841,7 +842,7 @@ func TestReplicationStateStore_requireState(t *testing.T) { } } -func TestClient_PreventDirtyReads(t *testing.T) { +func TestClient_ReadYourWrites(t *testing.T) { b64enc := func(s string) string { return base64.StdEncoding.EncodeToString([]byte(s)) } @@ -949,7 +950,7 @@ func TestClient_PreventDirtyReads(t *testing.T) { config, ln := testHTTPServer(t, handler) defer ln.Close() - config.PreventStaleReads = true + config.ReadYourWrites = true config.Address = fmt.Sprintf("http://%s", ln.Addr()) parent, err := NewClient(config) if err != nil { diff --git a/changelog/12814.txt b/changelog/12814.txt index 15b55631c851e..9d5b541d6d841 100644 --- a/changelog/12814.txt +++ b/changelog/12814.txt @@ -1,3 +1,3 @@ ```release-note:improvement -api: Add support for preventing stale reads by automatically requiring known cluster replication states in each request. +api: Add configuration option for ensuring isolated read-after-write semantics for all Client requests. ```