Last active
July 12, 2021 20:36
-
-
Save tidwall/b0d87956d8488a0b0e902f367babc439 to your computer and use it in GitHub Desktop.
Test Tile38 for Expiration Drift
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
// Test Tile38 for Expiration Drift | |
// Issue #616 | |
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"sync" | |
"time" | |
"github.com/gomodule/redigo/redis" | |
"github.com/tidwall/btree" | |
"github.com/tidwall/gjson" | |
"github.com/tidwall/sjson" | |
) | |
const exsecs = 10 | |
const key = "__issue_616__" | |
func makeID() string { | |
const chars = "0123456789abcdefghijklmnopqrstuvwxyz-" | |
var buf [10]byte | |
rand.Read(buf[:]) | |
for i := 0; i < len(buf); i++ { | |
buf[i] = chars[int(buf[i])%len(chars)] | |
} | |
return string(buf[:]) | |
} | |
func main() { | |
fmt.Printf( | |
"The SCAN and ACTUAL values should reach about 1850 and stay\n" + | |
"roughly the same from there on.\n") | |
var mu sync.Mutex | |
objs := btree.New(func(a, b interface{}) bool { | |
ajson := a.(string) | |
bjson := b.(string) | |
return gjson.Get(ajson, "id").String() < gjson.Get(bjson, "id").String() | |
}) | |
expires := btree.New(func(a, b interface{}) bool { | |
ajson := a.(string) | |
bjson := b.(string) | |
if gjson.Get(ajson, "properties.ex").Int() < gjson.Get(bjson, "properties.ex").Int() { | |
return true | |
} | |
if gjson.Get(ajson, "properties.ex").Int() > gjson.Get(bjson, "properties.ex").Int() { | |
return false | |
} | |
return gjson.Get(ajson, "id").String() < gjson.Get(bjson, "id").String() | |
}) | |
conn := must(redis.Dial("tcp", ":9851")).(redis.Conn) | |
must(conn.Do("DROP", key)) | |
must(nil, conn.Close()) | |
go func() { | |
conn := must(redis.Dial("tcp", ":9851")).(redis.Conn) | |
defer conn.Close() | |
for { | |
ex := time.Now().UnixNano() + int64(exsecs*time.Second) | |
for i := 0; i < 10; i++ { | |
id := makeID() | |
x := rand.Float64()*360 - 180 | |
y := rand.Float64()*180 - 90 | |
obj := fmt.Sprintf(`{"type":"Feature","geometry":{"type":"Point","coordinates":[%f,%f]},"properties":{}}`, x, y) | |
obj, _ = sjson.Set(obj, "properties.ex", ex) | |
obj, _ = sjson.Set(obj, "id", id) | |
res := must(redis.String(conn.Do("SET", key, id, "ex", exsecs, "OBJECT", obj))).(string) | |
if res != "OK" { | |
panic(fmt.Sprintf("expected 'OK', got '%s'", res)) | |
} | |
mu.Lock() | |
prev := objs.Set(obj) | |
if prev != nil { | |
expires.Delete(obj) | |
} | |
expires.Set(obj) | |
mu.Unlock() | |
} | |
time.Sleep(time.Second / 20) | |
} | |
}() | |
go func() { | |
conn := must(redis.Dial("tcp", ":9851")).(redis.Conn) | |
defer conn.Close() | |
for { | |
time.Sleep(time.Second * 5) | |
must(conn.Do("AOFSHRINK")) | |
} | |
}() | |
go func() { | |
conn := must(redis.Dial("tcp", ":9851")).(redis.Conn) | |
defer conn.Close() | |
must(conn.Do("OUTPUT", "JSON")) | |
for { | |
time.Sleep(time.Second / 10) | |
var ids []string | |
res := must(redis.String(conn.Do("SCAN", key, "LIMIT", 100000000))).(string) | |
gjson.Get(res, "objects").ForEach(func(_, res gjson.Result) bool { | |
ids = append(ids, res.Get("id").String()) | |
return true | |
}) | |
now := time.Now().UnixNano() | |
mu.Lock() | |
var exobjs []string | |
expires.Ascend(nil, func(v interface{}) bool { | |
ex := gjson.Get(v.(string), "properties.ex").Int() | |
if ex > now { | |
return false | |
} | |
exobjs = append(exobjs, v.(string)) | |
return true | |
}) | |
for _, obj := range exobjs { | |
objs.Delete(obj) | |
expires.Delete(obj) | |
} | |
fmt.Printf("\rSCAN: %d, ACTUAL: %d ", len(ids), objs.Len()) | |
mu.Unlock() | |
} | |
}() | |
select {} | |
} | |
func must(v interface{}, err error) interface{} { | |
if err != nil { | |
panic(err) | |
} | |
return v | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment