Skip to content

Commit 23bc542

Browse files
committed
use a more traditional linked list
1 parent 701c56a commit 23bc542

File tree

5 files changed

+166
-62
lines changed

5 files changed

+166
-62
lines changed

internal/server/redis/list.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package redis
33
import (
44
"context"
55
"fmt"
6-
"math"
76
"strconv"
87

98
"github.com/apple/foundationdb/bindings/go/src/fdb"
@@ -98,27 +97,43 @@ func (s *session) handlePush(ctx context.Context, args []resp.Value, left bool)
9897
if listMeta == nil {
9998
// create a new list
10099
listMeta = &types.ListMeta{
101-
Created: now,
102-
ItemStart: math.MaxUint64 / 2,
103-
ItemEnd: math.MaxUint64 / 2,
100+
Created: now,
104101
}
105102
}
106103

107-
// assign slots for these new list items and create object blobs for each
104+
// create each item meta object and store the blob itself
108105
for _, member := range members {
109-
listMeta.NumItems += 1
106+
objIDInt, err := s.allocateNewUID(ctx, tx)
107+
if err != nil {
108+
return nil, fmt.Errorf("failed to allocate new uid: %w", err)
109+
}
110+
objID := strconv.FormatUint(objIDInt, 10)
110111

111-
var objKeyInt uint64
112+
objMeta := &types.ListObjectMeta{
113+
Created: now,
114+
Updated: now,
115+
Id: objID,
116+
}
117+
118+
listMeta.NumItems += 1
112119
if left {
113-
listMeta.ItemStart -= 1
114-
objKeyInt = listMeta.ItemStart
120+
objMeta.Next = listMeta.ItemHead
121+
listMeta.ItemHead = objID
115122
} else {
116-
listMeta.ItemEnd += 1
117-
objKeyInt = listMeta.ItemEnd
123+
objMeta.Previous = listMeta.ItemTail
124+
listMeta.ItemTail = objID
125+
}
126+
127+
objMetaKey, err := s.listObjMetaKey(key, objID)
128+
if err != nil {
129+
return nil, fmt.Errorf("failed to get list object meta key: %w", err)
130+
}
131+
132+
if err := s.setProtoItem(objMetaKey, objMeta); err != nil {
133+
return nil, fmt.Errorf("failed to write list object meta: %w", err)
118134
}
119135

120-
objKey := strconv.FormatUint(objKeyInt, 10)
121-
if err := s.writeObject(ctx, tx, objKey, []byte(member)); err != nil {
136+
if err := s.writeObject(ctx, tx, objID, []byte(member)); err != nil {
122137
return nil, fmt.Errorf("failed to create object: %w", err)
123138
}
124139
}

internal/server/redis/redis.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,22 @@ func (s *session) listKey(id string) (fdb.Key, error) {
254254
return s.user.listDir.Pack(tuple.Tuple{id}), nil
255255
}
256256

257+
// Returns the FDB key of an object in the per-user, per-list item directory
258+
func (s *session) listObjMetaKey(listID, objID string) (fdb.Key, error) {
259+
s.userMu.RLock()
260+
defer s.userMu.RUnlock()
261+
262+
if s.user == nil {
263+
return nil, fmt.Errorf("authentication is required")
264+
}
265+
266+
dir, err := s.user.listDir.CreateOrOpen(s.fdb, []string{listID}, nil)
267+
if err != nil {
268+
return nil, fmt.Errorf("failed to open per-list directory: %w", err)
269+
}
270+
271+
return dir.Pack(tuple.Tuple{objID}), nil
272+
}
257273
func (s *session) write(msg string) {
258274
_, err := s.conn.Write([]byte(msg))
259275
if err != nil {

internal/server/redis/redis_test.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ package redis
33
import (
44
"bufio"
55
"bytes"
6-
"math"
76
"math/rand/v2"
87
"strings"
98
"testing"
109

1110
"github.com/apple/foundationdb/bindings/go/src/fdb"
1211
"github.com/bluesky-social/kvdb/internal/testutil"
13-
"github.com/bluesky-social/kvdb/internal/types"
1412
"github.com/bluesky-social/kvdb/pkg/serde/resp"
1513
"github.com/stretchr/testify/require"
1614
"golang.org/x/crypto/bcrypt"
@@ -962,21 +960,4 @@ func TestLists(t *testing.T) {
962960
Args: []resp.Value{resp.SimpleStringValue(list)},
963961
})
964962
require.Equal(resp.FormatInt(5), res)
965-
966-
{
967-
// ensure our item meta is correct
968-
metaAny, err := sess.fdb.ReadTransact(func(tx fdb.ReadTransaction) (any, error) {
969-
_, meta, err := sess.getListMeta(ctx, tx, list)
970-
return meta, err
971-
})
972-
require.NoError(err)
973-
require.NotNil(metaAny)
974-
975-
meta, err := cast[*types.ListMeta](metaAny)
976-
require.NoError(err)
977-
978-
mid := uint64(math.MaxUint64 / 2)
979-
require.Equal(mid-3, meta.ItemStart)
980-
require.Equal(mid+2, meta.ItemEnd)
981-
}
982963
}

internal/types/redis.pb.go

Lines changed: 112 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/types/redis.proto

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ message ListMeta {
3838
google.protobuf.Timestamp updated = 2;
3939
google.protobuf.Timestamp last_access = 3;
4040
uint64 num_items = 4;
41-
uint64 item_start = 5;
42-
uint64 item_end = 6;
41+
string item_head = 5;
42+
string item_tail= 6;
43+
}
44+
45+
message ListObjectMeta {
46+
google.protobuf.Timestamp created = 1;
47+
google.protobuf.Timestamp updated = 2;
48+
string id = 3;
49+
string next = 4;
50+
string previous = 5;
4351
}

0 commit comments

Comments
 (0)