Skip to content

Commit 576d8e0

Browse files
authored
Update bookmark manager API (#410)
As explained in ADR 011, Fabric combines bookmarks when multiple databases are involved in a single transaction so there is no need on the driver side to track databases at all.
1 parent f66f943 commit 576d8e0

File tree

15 files changed

+177
-394
lines changed

15 files changed

+177
-394
lines changed

neo4j/bookmarks.go

Lines changed: 30 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -34,132 +34,82 @@ type Bookmarks = []string
3434
// BookmarkManager centralizes bookmark manager supply and notification
3535
// This API is experimental and may be changed or removed without prior notice
3636
type BookmarkManager interface {
37-
// UpdateBookmarks updates the bookmark for the specified database
37+
// UpdateBookmarks updates the bookmark tracked by this bookmark manager
3838
// previousBookmarks are the initial bookmarks of the bookmark holder (like a Session)
3939
// newBookmarks are the bookmarks that are received after completion of the bookmark holder operation (like the end of a Session)
40-
UpdateBookmarks(ctx context.Context, database string, previousBookmarks, newBookmarks Bookmarks) error
40+
UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks Bookmarks) error
4141

42-
// GetAllBookmarks returns all the bookmarks tracked by this bookmark manager
43-
// Note: the order of the returned bookmark slice is not guaranteed
44-
GetAllBookmarks(ctx context.Context) (Bookmarks, error)
45-
46-
// GetBookmarks returns all the bookmarks associated with the specified database
42+
// GetBookmarks returns all the bookmarks tracked by this bookmark manager
4743
// Note: the order of the returned bookmark slice does not need to be deterministic
48-
GetBookmarks(ctx context.Context, database string) (Bookmarks, error)
49-
50-
// Forget removes all databases' bookmarks
51-
// Note: it is the driver user's responsibility to call this
52-
Forget(ctx context.Context, databases ...string) error
44+
GetBookmarks(ctx context.Context) (Bookmarks, error)
5345
}
5446

5547
// BookmarkManagerConfig is an experimental API and may be changed or removed
5648
// without prior notice
5749
type BookmarkManagerConfig struct {
5850
// Initial bookmarks per database
59-
InitialBookmarks map[string]Bookmarks
51+
InitialBookmarks Bookmarks
6052

6153
// Supplier providing external bookmarks
62-
BookmarkSupplier BookmarkSupplier
54+
BookmarkSupplier func(context.Context) (Bookmarks, error)
6355

64-
// Hook called whenever bookmarks for a given database get updated
56+
// Hook called whenever bookmarks get updated
6557
// The hook is called with the database and the new bookmarks
6658
// Note: the order of the supplied bookmark slice is not guaranteed
67-
BookmarkConsumer func(ctx context.Context, database string, bookmarks Bookmarks) error
68-
}
69-
70-
type BookmarkSupplier interface {
71-
// GetAllBookmarks returns all known bookmarks to the bookmark manager
72-
GetAllBookmarks(ctx context.Context) (Bookmarks, error)
73-
74-
// GetBookmarks returns all the bookmarks of the specified database to the bookmark manager
75-
GetBookmarks(ctx context.Context, database string) (Bookmarks, error)
59+
BookmarkConsumer func(ctx context.Context, bookmarks Bookmarks) error
7660
}
7761

7862
type bookmarkManager struct {
79-
bookmarks *sync.Map
80-
supplier BookmarkSupplier
81-
consumer func(context.Context, string, Bookmarks) error
63+
bookmarks collection.Set[string]
64+
supplyBookmarks func(context.Context) (Bookmarks, error)
65+
consumeBookmarks func(context.Context, Bookmarks) error
66+
mutex sync.RWMutex
8267
}
8368

84-
func (b *bookmarkManager) UpdateBookmarks(ctx context.Context, database string, previousBookmarks, newBookmarks Bookmarks) error {
69+
func (b *bookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks Bookmarks) error {
8570
if len(newBookmarks) == 0 {
8671
return nil
8772
}
73+
b.mutex.Lock()
74+
defer b.mutex.Unlock()
8875
var bookmarksToNotify Bookmarks
89-
storedNewBookmarks := collection.NewSet(newBookmarks)
90-
if rawCurrentBookmarks, loaded := b.bookmarks.LoadOrStore(database, storedNewBookmarks); !loaded {
91-
bookmarksToNotify = storedNewBookmarks.Values()
92-
} else {
93-
currentBookmarks := (rawCurrentBookmarks).(collection.Set[string])
94-
currentBookmarks.RemoveAll(previousBookmarks)
95-
currentBookmarks.AddAll(newBookmarks)
96-
bookmarksToNotify = currentBookmarks.Values()
97-
}
98-
if b.consumer != nil {
99-
return b.consumer(ctx, database, bookmarksToNotify)
76+
b.bookmarks.RemoveAll(previousBookmarks)
77+
b.bookmarks.AddAll(newBookmarks)
78+
bookmarksToNotify = b.bookmarks.Values()
79+
if b.consumeBookmarks != nil {
80+
return b.consumeBookmarks(ctx, bookmarksToNotify)
10081
}
10182
return nil
10283
}
10384

104-
func (b *bookmarkManager) GetAllBookmarks(ctx context.Context) (Bookmarks, error) {
105-
allBookmarks := collection.NewSet([]string{})
106-
if b.supplier != nil {
107-
bookmarks, err := b.supplier.GetAllBookmarks(ctx)
108-
if err != nil {
109-
return nil, err
110-
}
111-
allBookmarks.AddAll(bookmarks)
112-
}
113-
b.bookmarks.Range(func(db, rawBookmarks any) bool {
114-
bookmarks := rawBookmarks.(collection.Set[string])
115-
allBookmarks.Union(bookmarks)
116-
return true
117-
})
118-
return allBookmarks.Values(), nil
119-
}
120-
121-
func (b *bookmarkManager) GetBookmarks(ctx context.Context, database string) (Bookmarks, error) {
85+
func (b *bookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, error) {
12286
var extraBookmarks Bookmarks
123-
if b.supplier != nil {
124-
bookmarks, err := b.supplier.GetBookmarks(ctx, database)
87+
if b.supplyBookmarks != nil {
88+
bookmarks, err := b.supplyBookmarks(ctx)
12589
if err != nil {
12690
return nil, err
12791
}
12892
extraBookmarks = bookmarks
12993
}
130-
rawBookmarks, found := b.bookmarks.Load(database)
131-
if !found {
94+
b.mutex.RLock()
95+
defer b.mutex.RUnlock()
96+
if len(b.bookmarks) == 0 {
13297
return extraBookmarks, nil
13398
}
134-
bookmarks := rawBookmarks.(collection.Set[string]).Copy()
99+
bookmarks := b.bookmarks.Copy()
135100
if extraBookmarks == nil {
136101
return bookmarks.Values(), nil
137102
}
138103
bookmarks.AddAll(extraBookmarks)
139104
return bookmarks.Values(), nil
140105
}
141106

142-
func (b *bookmarkManager) Forget(ctx context.Context, databases ...string) error {
143-
for _, db := range databases {
144-
b.bookmarks.Delete(db)
145-
}
146-
return nil
147-
}
148-
149107
func NewBookmarkManager(config BookmarkManagerConfig) BookmarkManager {
150108
return &bookmarkManager{
151-
bookmarks: initializeBookmarks(config.InitialBookmarks),
152-
supplier: config.BookmarkSupplier,
153-
consumer: config.BookmarkConsumer,
154-
}
155-
}
156-
157-
func initializeBookmarks(allBookmarks map[string]Bookmarks) *sync.Map {
158-
var initialBookmarks sync.Map
159-
for db, bookmarks := range allBookmarks {
160-
initialBookmarks.Store(db, collection.NewSet(bookmarks))
109+
bookmarks: collection.NewSet(config.InitialBookmarks),
110+
supplyBookmarks: config.BookmarkSupplier,
111+
consumeBookmarks: config.BookmarkConsumer,
161112
}
162-
return &initialBookmarks
163113
}
164114

165115
// CombineBookmarks is a helper method to combine []Bookmarks into a single Bookmarks instance.

0 commit comments

Comments
 (0)