In-game leaderboard is a very common requirement, previously used by Redis SortedSet, just see a LUA implementation, and then ported to the Golang version, GitHub address: Https://github.com/Skycrab/go-zset , the CLI commands for using the method and Redis are basically consistent.
Using the CGO package, the implementation of the skiplist is basically the same as Redis, although CGO is very convenient to use, but it involves a callback to go in C.
It doesn't feel like Lua is refreshing.
Go-zet does not provide a way to persist, and I provide persistence in Https://github.com/Skycrab/cham/blob/master/lib/zset/zset.go . There is primarily no good persistence scheme, unlike the RDB format used by Redis. In Cham, like Redis, the fork writes the file,
It's just that I'm using the JSON format.
Use fork snapshot to Savefunc (z *zset) bgstore (name string) error {F, err: = Helper. LockFile (name, true) if err! = Nil {return err}pid, errno: = helper. Fork () if errno! = 0 {return errors. New ("fork error," + errno. Error ())}//childif pid = = 0 {buf: = Bufio. Newwriter (f) Encoder: = json. Newencoder (BUF) encoder. Encode (Z.TBL) buf. Flush () f.close () OS. Exit (0)}return Nil}
The helper code is as follows:
Package Helperimport ("OS" "Runtime" "Syscall") func Fork () (int, syscall. Errno) {r1, r2, err: = Syscall. Rawsyscall (Syscall. Sys_fork, 0, 0, 0) if Err! = 0 {return 0, err}if runtime. GOOS = = "Darwin" && r2 = = 1 {r1 = 1}return int (r1), 0}//referer http://ikarishinjieva.github.io/blog/blog/2014/03 /20/go-file-lock/func LockFile (name string, truncate BOOL) (*os. File, error) {flag: = OS. O_rdwr | Os. O_createif truncate {flag |= OS. O_trunc}f, err: = OS. OpenFile (name, flag, 0666) if err! = Nil {return nil, err}if err: = Syscall. Flock (int (F.FD ()), Syscall. Lock_ex|syscall. LOCK_NB); Err! = Nil {f.close () return nil, Err}return F, nil}
Let's see if test basically knows how to use it.
Package Zsetimport ("FMT" "Testing" "time") func equal (a []string, b []string) bool {if Len (a)! = Len (b) {return false}for I : = 0; I < Len (a); i++ {if a[i]! = B[i] {return False}}return True}func assert (t *testing. T, OK bool, s string) {if!ok {t.error (s)}}func testbase (t *testing. T) {z: = New () assert (T, z.count () = = 0, "Empty Count Error") Z.add (1, "") Z.add (1, "+") assert (T, z.count () = = 2, "not EMP Ty Count error ") VAR score float64var ex Boolscore, ex = Z.score (" a ") assert (t, score = = 1," score Error ") Z.add (2," a ") ERT (T, z.count () = = 2, "After add duplicate Count error") score, ex = Z.score ("a") assert (t, score = 2, "After add score E Rror ") Z.rem (" a ") assert (T, z.count () = = 1," After Rem Count error ") score, ex = Z.score (" a ") assert (t, ex = = False," not ex IST score Error ") FMT. Println ("")}func Testrangebyscore (t *testing. T) {z: = New () z.add (2, "a") Z.add (1, "one") Z.add (3, "") s: = "Testrangebyscore error" assert (T, equal (Z.rangebyscore (2, 3) , []string{"," + "}), s) assert (T, equal (Z.rangebyscore (0, 5), []string{"one", "Max", "Max"}), s) assert (T, equal (Z.rangebyscore (5), []string{}), s) assert (T, Equal (Z.rangebyscore (0), []string{"", "" "," one "}), s)}func testrange (t *testing. T) {z: = New () z.add (100.1, "1") Z.add (100.9, "9") Z.add (100.5, "5") assert (T, equal (Z.range (1, 3), []string{"1", "5", "9"}), "Range1 error") assert (T, equal (Z.range (3, 1), []string{"9", "5", "1"}), "Range2 error") assert (T, equal (Z.revrange (1, 2), []string{"9", "5"}), "RevRange1 error") assert (T, equal (Z.revrange (3, 2), []string{"1", "5"}), "RevRange2 error")}func Te Strank (t *testing. T) {z: = New () assert (T, Z.rank ("kehan") = = 0, "Rank empty Error") Z.add (1111.1111, "Kehan") assert (T, Z.rank ("kehan") = = 1, "Rank error") Z.add (222.2222, "Lwy") assert (T, Z.rank ("kehan") = = 2, "Rank 2 Error") assert (T, Z.revrank ("kehan") = = 1, "REVR Ank error ")}func Testlimit (t *testing. T) {z: = New () z.add (1, "1") Z.add (2, "2") Z.add (3, "3") Z.limit (1) assert (T, z.count () = = 1, "Limit error") assert (T, Z.rank ("3 ") = = 0," LImit Rank Error ") Z.add (4.4," 4 ") Z.add (5.5," 5 ") Z.add (0.5," 0.5 ") Z.dump () assert (T, z.revlimit (4) = = 0," Revlimit error ") ASSERT (T, z.revlimit (0) = = 4, "RevLimit2 error")}func Teststore (t *testing. T) {z: = New () z.add (1, "1") Z.add (2, "2") Z.add (3, "3") Z.bgstore ("Zdb.json") go func () {time. Sleep (time. Second * 2) FMT. Println ("continue add") Z.add (4, "4") Z.add (5, "5")} ()}func Testrestore (t *testing. T) {z: = New () assert (T, len (z.tbl) = = 0, "restore Error") Z.restore ("Zdb.json") fmt. Println (Z.TBL) assert (T, Len (Z.TBL)! = 0, "Restore2 error") assert (T, z.count () = = Len (z.tbl), "Restore3 Error")}
Golang SortedSet Implementation (Redis skiplist based)