Skip to content

Commit cc4f5ce

Browse files
authored
Merge pull request #16 from Arkiv-Network/batch-bitmap-writes
Batch bitmap writes
2 parents be5c0ac + 8f494ce commit cc4f5ce

File tree

8 files changed

+1326
-220
lines changed

8 files changed

+1326
-220
lines changed

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"Bash(go doc:*)",
99
"Bash(go get:*)",
1010
"Bash(go test:*)",
11-
"Bash(go mod tidy:*)"
11+
"Bash(go mod tidy:*)",
12+
"Bash(mkdir:*)"
1213
]
1314
}
1415
}

.github/workflows/test.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Go Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: "1.25.4"
20+
21+
- name: Install dependencies
22+
run: go mod download
23+
24+
- name: Run tests
25+
run: go test -v ./...

bitmap_cache.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package sqlitebitmapstore
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"fmt"
7+
8+
"github.com/Arkiv-Network/sqlite-bitmap-store/store"
9+
)
10+
11+
type nameValue[T any] struct {
12+
name string
13+
value T
14+
}
15+
16+
type bitmapCache struct {
17+
st store.Querier
18+
19+
stringBitmaps map[nameValue[string]]*store.Bitmap
20+
numericBitmaps map[nameValue[uint64]]*store.Bitmap
21+
}
22+
23+
func newBitmapCache(st store.Querier) *bitmapCache {
24+
return &bitmapCache{
25+
st: st,
26+
stringBitmaps: make(map[nameValue[string]]*store.Bitmap),
27+
numericBitmaps: make(map[nameValue[uint64]]*store.Bitmap),
28+
}
29+
}
30+
31+
func (c *bitmapCache) AddToStringBitmap(ctx context.Context, name string, value string, id uint64) (err error) {
32+
k := nameValue[string]{name: name, value: value}
33+
bitmap, ok := c.stringBitmaps[k]
34+
if !ok {
35+
bitmap, err = c.st.GetStringAttributeValueBitmap(ctx, store.GetStringAttributeValueBitmapParams{Name: name, Value: value})
36+
37+
if err != nil && err != sql.ErrNoRows {
38+
return fmt.Errorf("failed to get string attribute %q value %q bitmap: %w", name, value, err)
39+
}
40+
41+
if bitmap == nil {
42+
bitmap = store.NewBitmap()
43+
}
44+
45+
c.stringBitmaps[k] = bitmap
46+
}
47+
48+
bitmap.Add(id)
49+
50+
return nil
51+
52+
}
53+
54+
func (c *bitmapCache) RemoveFromStringBitmap(ctx context.Context, name string, value string, id uint64) (err error) {
55+
k := nameValue[string]{name: name, value: value}
56+
bitmap, ok := c.stringBitmaps[k]
57+
if !ok {
58+
bitmap, err = c.st.GetStringAttributeValueBitmap(ctx, store.GetStringAttributeValueBitmapParams{Name: name, Value: value})
59+
60+
if err != nil && err != sql.ErrNoRows {
61+
return fmt.Errorf("failed to get string attribute %q value %q bitmap: %w", name, value, err)
62+
}
63+
64+
if bitmap == nil {
65+
bitmap = store.NewBitmap()
66+
}
67+
68+
c.stringBitmaps[k] = bitmap
69+
}
70+
71+
bitmap.Remove(id)
72+
73+
return nil
74+
75+
}
76+
77+
func (c *bitmapCache) AddToNumericBitmap(ctx context.Context, name string, value uint64, id uint64) (err error) {
78+
k := nameValue[uint64]{name: name, value: value}
79+
bitmap, ok := c.numericBitmaps[k]
80+
if !ok {
81+
bitmap, err = c.st.GetNumericAttributeValueBitmap(ctx, store.GetNumericAttributeValueBitmapParams{Name: name, Value: value})
82+
83+
if err != nil && err != sql.ErrNoRows {
84+
return fmt.Errorf("failed to get numeric attribute %q value %q bitmap: %w", name, value, err)
85+
}
86+
87+
if bitmap == nil {
88+
bitmap = store.NewBitmap()
89+
}
90+
91+
c.numericBitmaps[k] = bitmap
92+
}
93+
94+
bitmap.Add(id)
95+
96+
return nil
97+
98+
}
99+
100+
func (c *bitmapCache) RemoveFromNumericBitmap(ctx context.Context, name string, value uint64, id uint64) (err error) {
101+
k := nameValue[uint64]{name: name, value: value}
102+
bitmap, ok := c.numericBitmaps[k]
103+
if !ok {
104+
bitmap, err = c.st.GetNumericAttributeValueBitmap(ctx, store.GetNumericAttributeValueBitmapParams{Name: name, Value: value})
105+
106+
if err != nil && err != sql.ErrNoRows {
107+
return fmt.Errorf("failed to get numeric attribute %q value %q bitmap: %w", name, value, err)
108+
}
109+
110+
if bitmap == nil {
111+
bitmap = store.NewBitmap()
112+
}
113+
114+
c.numericBitmaps[k] = bitmap
115+
}
116+
117+
bitmap.Remove(id)
118+
119+
return nil
120+
121+
}
122+
123+
func (c *bitmapCache) Flush(ctx context.Context) (err error) {
124+
for k, bitmap := range c.stringBitmaps {
125+
126+
if bitmap.IsEmpty() {
127+
err = c.st.DeleteStringAttributeValueBitmap(ctx, store.DeleteStringAttributeValueBitmapParams{Name: k.name, Value: k.value})
128+
if err != nil {
129+
return fmt.Errorf("failed to delete string attribute %q value %q bitmap: %w", k.name, k.value, err)
130+
}
131+
continue
132+
}
133+
134+
bitmap.RunOptimize()
135+
136+
err = c.st.UpsertStringAttributeValueBitmap(ctx, store.UpsertStringAttributeValueBitmapParams{Name: k.name, Value: k.value, Bitmap: bitmap})
137+
if err != nil {
138+
return fmt.Errorf("failed to upsert string attribute %q value %q bitmap: %w", k.name, k.value, err)
139+
}
140+
}
141+
142+
for k, bitmap := range c.numericBitmaps {
143+
144+
if bitmap.IsEmpty() {
145+
err = c.st.DeleteNumericAttributeValueBitmap(ctx, store.DeleteNumericAttributeValueBitmapParams{Name: k.name, Value: k.value})
146+
if err != nil {
147+
return fmt.Errorf("failed to delete numeric attribute %q value %q bitmap: %w", k.name, k.value, err)
148+
}
149+
continue
150+
}
151+
152+
bitmap.RunOptimize()
153+
154+
err = c.st.UpsertNumericAttributeValueBitmap(ctx, store.UpsertNumericAttributeValueBitmapParams{Name: k.name, Value: k.value, Bitmap: bitmap})
155+
if err != nil {
156+
return fmt.Errorf("failed to upsert numeric attribute %q value %q bitmap: %w", k.name, k.value, err)
157+
}
158+
}
159+
return nil
160+
}

numeric_bitmap_ops.go

Lines changed: 0 additions & 95 deletions
This file was deleted.

0 commit comments

Comments
 (0)