Skip to content

Commit 6cf4257

Browse files
authored
Merge branch 'main' into 3318-RavenDB-state-store-new
2 parents 701d8f0 + aa622c3 commit 6cf4257

File tree

2 files changed

+88
-13
lines changed

2 files changed

+88
-13
lines changed

state/redis/redis.go

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -465,19 +465,43 @@ func (r *StateStore) registerSchemas(ctx context.Context) error {
465465
return nil
466466
}
467467

468-
func (r *StateStore) getKeyVersion(vals []interface{}) (data string, version *string, err error) {
469-
seenData := false
470-
seenVersion := false
471-
for i := 0; i < len(vals); i += 2 {
472-
field, _ := strconv.Unquote(fmt.Sprintf("%q", vals[i]))
473-
switch field {
474-
case "data":
475-
data, _ = strconv.Unquote(fmt.Sprintf("%q", vals[i+1]))
476-
seenData = true
477-
case "version":
478-
versionVal, _ := strconv.Unquote(fmt.Sprintf("%q", vals[i+1]))
479-
version = ptr.Of(versionVal)
480-
seenVersion = true
468+
func (r *StateStore) getKeyVersion(vals []any) (data string, version *string, err error) {
469+
var seenData, seenVersion bool
470+
471+
// step by 2: key, value. we only expect string or byte slice
472+
for i := 0; i+1 < len(vals); i += 2 {
473+
switch key := vals[i].(type) {
474+
case string:
475+
switch key {
476+
case "data":
477+
if s, ok := toString(vals[i+1]); ok {
478+
data = s
479+
seenData = true
480+
}
481+
case "version":
482+
if s, ok := toString(vals[i+1]); ok {
483+
version = &s
484+
seenVersion = true
485+
}
486+
}
487+
case []byte:
488+
switch string(key) {
489+
case "data":
490+
if s, ok := toString(vals[i+1]); ok {
491+
data = s
492+
seenData = true
493+
}
494+
case "version":
495+
if s, ok := toString(vals[i+1]); ok {
496+
version = &s
497+
seenVersion = true
498+
}
499+
}
500+
}
501+
502+
// Early exit once both values have been found
503+
if seenData && seenVersion {
504+
break
481505
}
482506
}
483507
if !seenData || !seenVersion {
@@ -487,6 +511,17 @@ func (r *StateStore) getKeyVersion(vals []interface{}) (data string, version *st
487511
return data, version, nil
488512
}
489513

514+
func toString(v any) (string, bool) {
515+
switch x := v.(type) {
516+
case string:
517+
return x, true
518+
case []byte:
519+
return string(x), true // some allocation here unless we go to unsafe: return unsafe.String(unsafe.SliceData(x), len(x)), true
520+
default:
521+
return "", false
522+
}
523+
}
524+
490525
func (r *StateStore) parseETag(req *state.SetRequest) (int, error) {
491526
if req.Options.Concurrency == state.LastWrite || req.ETag == nil || *req.ETag == "" {
492527
return 0, nil

state/redis/redis_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,43 @@ func setupMiniredis() (*miniredis.Miniredis, rediscomponent.RedisClient) {
521521

522522
return s, rediscomponent.ClientFromV8Client(redis.NewClient(opts))
523523
}
524+
525+
func TestToString(t *testing.T) {
526+
// happy paths
527+
if s, ok := toString("abc"); assert.True(t, ok) {
528+
assert.Equal(t, "abc", s)
529+
}
530+
if s, ok := toString([]byte("def")); assert.True(t, ok) {
531+
assert.Equal(t, "def", s)
532+
}
533+
// unsupported
534+
_, ok := toString(123)
535+
assert.False(t, ok)
536+
}
537+
538+
func BenchmarkGetKeyVersion(b *testing.B) {
539+
/*
540+
On a Mac M1 Pro:
541+
BenchmarkGetKeyVersion-10 13651144 83.84 ns/op 64 B/op 6 allocs/op
542+
543+
// old getkeyversion method
544+
BenchmarkGetKeyVersionOld-10 1631097 729.1 ns/op 96 B/op 10 allocs/op
545+
546+
// ~8x speed - ~1/2 allocations
547+
548+
// unsafe comparison
549+
BenchmarkGetKeyVersion-10 28636363 41.53 ns/op 32 B/op 2 allocs/op
550+
*/
551+
store := newStateStore(logger.NewLogger("bench"))
552+
input1 := []any{[]byte("data"), []byte("payload"), []byte("version"), []byte("42")}
553+
input2 := []any{[]byte("data"), []byte("payload2"), []byte("version"), []byte("43")}
554+
b.ReportAllocs()
555+
for range b.N {
556+
if _, _, err := store.getKeyVersion(input1); err != nil {
557+
b.Fatal(err)
558+
}
559+
if _, _, err := store.getKeyVersion(input2); err != nil {
560+
b.Fatal(err)
561+
}
562+
}
563+
}

0 commit comments

Comments
 (0)