-
Notifications
You must be signed in to change notification settings - Fork 470
DisableCAS support #113
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
Closed
Closed
DisableCAS support #113
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
1af313e
DisableCAS support
a9efc0f
Merge branch 'bradfitz:master' into master
lovelock 7982c31
provide roundrobin server selector for some non-standard memcache ser…
3f0e2e4
version v3
21e132d
version v3.0.2
51ed349
version upgrade
7f1081b
document more
7cb416e
fix typo in doc
bdca2e8
modify vulnerable statements according to SA4011
4dfff16
use write lock instead of read lock
1f8d01b
keep pace with upstream
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| _* | ||
| *.out | ||
| *~ | ||
| .idea/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,80 @@ | ||
| ## About | ||
|
|
||
| This is a memcache client library for the Go programming language | ||
| This is a memcache client library derived from [gomemcache](https://github.com/bradfitz/gomemcache) for the Go programming language | ||
| (http://golang.org/). | ||
|
|
||
| ## Example | ||
| ## Why this project? | ||
|
|
||
| Install with: | ||
| The version is bumped to v3 to indicate that it has something incompatible with the vanilla one. | ||
|
|
||
| ### `get` vs `gets` | ||
|
|
||
| There are many derivate servers which implement **incomplete** memcache prototol, e.g. only `get` and `set` are implemented. | ||
|
|
||
| The thing is, the original repository of [gomemcache](https://github.com/bradfitz/gomemcache) has something confusing when it comes to [`get` command](https://github.com/bradfitz/gomemcache/blob/fb4bf637b56d66a1925c1bb0780b27dd714ec380/memcache/memcache.go#L361). | ||
|
|
||
| ```shell | ||
| $ go get github.com/bradfitz/gomemcache/memcache | ||
| ```go | ||
| if _, err := fmt.Fprintf(rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil { | ||
| return err | ||
| } | ||
| ``` | ||
|
|
||
| Then use it like: | ||
| It means when you call `get`, the `gets` command is executed and [`casid` is always returned](https://github.com/bradfitz/gomemcache/blob/fb4bf637b56d66a1925c1bb0780b27dd714ec380/memcache/memcache.go#L523). | ||
|
|
||
| ```go | ||
| dest := []interface{}{&it.Key, &it.Flags, &size, &it.casid} | ||
| ``` | ||
|
|
||
| I've talked to bradfitz and got a lot of important advises from him. Truly all the things I mentioned above are all because of the **incomplete implementation** and have nothing to do with the client. What I stand for is `get` means `get` and `gets` means `gets`. | ||
|
|
||
| ### `RoundRobinServerSelector` | ||
|
|
||
| Vanilla memcache server use crc32 to pick which server to store a key, for servers those distribute keys equally to all nodes the crc32 is not what is wanted. Thanks for bradfitz's brilliant work I can implement a `RoundRobinServerSelector` painlessly. | ||
|
|
||
| ## Installing | ||
|
|
||
| ### Using _go get_ | ||
|
|
||
| `$ go get -u github.com/lovelock/gomemcache/v3/memcache` | ||
|
|
||
| After this command _gomemcache_ is ready to use. Its source will be in: | ||
|
|
||
| `$GOPATH/src/github.com/lovelock/gomemcache/memcache` | ||
|
|
||
| ## Example | ||
|
|
||
| Install with: | ||
| ```go | ||
| import ( | ||
| "github.com/bradfitz/gomemcache/memcache" | ||
| "github.com/lovelock/gomemcache/v3/memcache" | ||
| ) | ||
|
|
||
| func main() { | ||
| mc := memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212") | ||
| mc.Set(&memcache.Item{Key: "foo", Value: []byte("my value")}) | ||
| } | ||
| ``` | ||
|
|
||
| ### For other derivatives | ||
|
|
||
| it, err := mc.Get("foo") | ||
| ... | ||
| ```go | ||
| import ( | ||
| "github.com/lovelock/gomemcache/v3/memcache" | ||
| ) | ||
|
|
||
| func main() { | ||
| mc := memcache.NewRoundRobin("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212") | ||
| mc.DisableCAS = true // don't want get casid | ||
| mc.Set(&memcache.Item{Key: "foo", Value: []byte("my value")}) | ||
|
|
||
| it, err := mc.Get("foo") | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ## Full docs, see: | ||
|
|
||
| See https://pkg.go.dev/github.com/bradfitz/gomemcache/memcache | ||
| See https://godoc.org/github.com/lovelock/gomemcache/v3/memcache | ||
|
|
||
| Or run: | ||
|
|
||
| ```shell | ||
| $ godoc github.com/bradfitz/gomemcache/memcache | ||
| ``` | ||
|
|
||
| `$ godoc github.com/lovelock/gomemcache/v3/memcache` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| module github.com/bradfitz/gomemcache | ||
| module github.com/lovelock/gomemcache/v3 | ||
|
|
||
| go 1.18 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| package memcache | ||
|
|
||
| import ( | ||
| "net" | ||
| "strings" | ||
| "sync" | ||
| ) | ||
|
|
||
| // NewRoundRobin returns a memcache client using the provided server(s) | ||
| // with equal weight. If a server is listed multiple times, | ||
| // it gets a proportional amount of weight. | ||
| func NewRoundRobin(server ...string) *Client { | ||
| ss := new(RoundRobinServerList) | ||
| err := ss.SetServers(server...) | ||
| if err != nil { | ||
| return nil | ||
| } | ||
|
|
||
| return NewFromRoundRobinSelector(ss) | ||
| } | ||
|
|
||
| // NewFromRoundRobinSelector returns a new Client using the provided RoundRobinServerSelector. | ||
| func NewFromRoundRobinSelector(ss *RoundRobinServerList) *Client { | ||
| return &Client{ | ||
| selector: ss, | ||
| DisableCAS: false, | ||
| } | ||
| } | ||
|
|
||
| // RoundRobinServerList is a simple ServerSelector. Its zero value is usable. | ||
| type RoundRobinServerList struct { | ||
| mu sync.Mutex | ||
| addrs []net.Addr | ||
| next int | ||
| } | ||
|
|
||
| // SetServers changes a RoundRobinServerList's set of servers at runtime and is | ||
| // safe for concurrent use by multiple goroutines. | ||
| // | ||
| // Each server is given equal weight. A server is given more weight | ||
| // if it's listed multiple times. | ||
| // | ||
| // SetServers returns an error if any of the server names fail to | ||
| // resolve. No attempt is made to connect to the server. If any error | ||
| // is returned, no changes are made to the RoundRobinServerList. | ||
| func (ss *RoundRobinServerList) SetServers(servers ...string) error { | ||
| naddr := make([]net.Addr, len(servers)) | ||
| for i, server := range servers { | ||
| if strings.Contains(server, "/") { | ||
| addr, err := net.ResolveUnixAddr("unix", server) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| naddr[i] = newStaticAddr(addr) | ||
| } else { | ||
| tcpaddr, err := net.ResolveTCPAddr("tcp", server) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| naddr[i] = newStaticAddr(tcpaddr) | ||
| } | ||
| } | ||
|
|
||
| ss.mu.Lock() | ||
| defer ss.mu.Unlock() | ||
| ss.addrs = naddr | ||
| return nil | ||
| } | ||
|
|
||
| // Each iterates over each server calling the given function | ||
| func (ss *RoundRobinServerList) Each(f func(net.Addr) error) error { | ||
| ss.mu.Lock() | ||
| defer ss.mu.Unlock() | ||
| for _, a := range ss.addrs { | ||
| if err := f(a); nil != err { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func (ss *RoundRobinServerList) PickServer(key string) (net.Addr, error) { | ||
| ss.mu.Lock() | ||
| defer ss.mu.Unlock() | ||
| if len(ss.addrs) == 0 { | ||
| return nil, ErrNoServers | ||
| } | ||
| if len(ss.addrs) == 1 { | ||
| return ss.addrs[0], nil | ||
| } | ||
|
|
||
| ss.next = (ss.next + 1) % len(ss.addrs) | ||
|
|
||
| return ss.addrs[ss.next], nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package memcache | ||
|
|
||
| import "testing" | ||
|
|
||
| func BenchmarkPickRoundRobinServer(b *testing.B) { | ||
| // at least two to avoid 0 and 1 special cases: | ||
| benchPickRoundRobinServer(b, "127.0.0.1:1234", "127.0.0.1:1235") | ||
| } | ||
|
|
||
| func BenchmarkPickRoundRobinServer_Single(b *testing.B) { | ||
| benchPickRoundRobinServer(b, "127.0.0.1:1234") | ||
| } | ||
|
|
||
| func benchPickRoundRobinServer(b *testing.B, servers ...string) { | ||
| b.ReportAllocs() | ||
| var ss RoundRobinServerList | ||
| ss.SetServers(servers...) | ||
| for i := 0; i < b.N; i++ { | ||
| if _, err := ss.PickServer("some key"); err != nil { | ||
| b.Fatal(err) | ||
| } | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
it looks like the meat of this PR is here... the DisableCAS bool that changes the command sent.