-
Notifications
You must be signed in to change notification settings - Fork 105
Change the data storage path structure for property model #955
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Updates the property model’s on-disk layout to be group-aware, so shards are stored under per-group directories, and adjusts repair/snapshot/gossip logic and tests accordingly.
Changes:
- Store property shards under
<property-dir>/<group>/shard-<id>/...and load/query/delete across group-scoped shard sets. - Update repair tree building, snapshotting, and repair gossip flows to operate with group-scoped shards/snapshots.
- Refresh generated API reference docs and add a breaking-change note to
CHANGES.md.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/api-reference.md | Updates generated API docs for TopNList.Item fields. |
| banyand/property/test_helper.go | Updates test helper to use new loadShard(group, id) signature. |
| banyand/property/shard_test.go | Adjusts shard tests for group-aware shard loading. |
| banyand/property/shard.go | Writes shards under a group directory and tags metrics with group. |
| banyand/property/repair_test.go | Updates repair tests for group-aware shard loading and tree reader signature. |
| banyand/property/repair_gossip_test.go | Updates gossip tests to snapshot/load shards per group. |
| banyand/property/repair_gossip.go | Loads shards by group and uses the updated tree reader API. |
| banyand/property/repair.go | Adjusts repair tree/state paths and rebuild logic for the new layout. |
| banyand/property/listener.go | Takes snapshots into group-scoped directories. |
| banyand/property/db.go | Introduces group→shards mapping and routes operations by group. |
| CHANGES.md | Documents the breaking storage layout change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
banyand/property/db.go
Outdated
| (*groupsMap)[group] = gs | ||
| db.groups.Store(groupsMap) |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getOrCreateGroupShards mutates the existing map[string]*groupShards in-place ((*groupsMap)[group] = gs) and then re-stores the same map pointer. Callers like delete/query/collect/close iterate over *groupsMap without holding db.mu, so this can trigger concurrent map iteration and map write panics. Use copy-on-write (allocate a new map, copy entries, add the new group, then Store the new pointer) or protect all reads with the same lock used for writes.
| (*groupsMap)[group] = gs | |
| db.groups.Store(groupsMap) | |
| // Use copy-on-write: create a new map, copy existing entries, then add the new group. | |
| oldMap := *groupsMap | |
| newMap := make(map[string]*groupShards, len(oldMap)+1) | |
| for k, v := range oldMap { | |
| newMap[k] = v | |
| } | |
| newMap[group] = gs | |
| db.groups.Store(&newMap) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use sync.Map to fix it.
| gs.mu.Lock() | ||
| sLst := gs.shards.Load() | ||
| if sLst == nil { | ||
| sLst = &[]*shard{} | ||
| } | ||
| *sLst = append(*sLst, sd) | ||
| db.sLst.Store(sLst) | ||
| newList := append(*sLst, sd) | ||
| gs.shards.Store(&newList) |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newList := append(*sLst, sd) can reuse the backing array of *sLst and mutate it in-place. Since readers access gs.shards.Load() without taking gs.mu, this can cause data races / inconsistent reads. Build the new slice with a guaranteed new backing array (e.g., copy to a fresh slice before appending) before storing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix it.
Co-authored-by: Copilot <[email protected]>
| gs.mu.Lock() | ||
| sLst := gs.shards.Load() | ||
| if sLst == nil { | ||
| sLst = &[]*shard{} | ||
| } | ||
| *sLst = append(*sLst, sd) | ||
| db.sLst.Store(sLst) | ||
| newList := append(*sLst, sd) | ||
| gs.shards.Store(&newList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix it.
banyand/property/db.go
Outdated
| (*groupsMap)[group] = gs | ||
| db.groups.Store(groupsMap) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use sync.Map to fix it.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #955 +/- ##
==========================================
+ Coverage 45.97% 47.19% +1.21%
==========================================
Files 328 383 +55
Lines 55505 59611 +4106
==========================================
+ Hits 25520 28131 +2611
- Misses 27909 28849 +940
- Partials 2076 2631 +555
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
banyand/property/listener.go:272
- This always returns a Snapshot{Name: sn,...} even if no shards were actually snapshotted (e.g., db.groups is empty or all gs.shards are nil), which means no snapshot directory gets created. Previously the code returned a nil payload when there were no shards. Consider returning nil/an error Snapshot in the “nothing snapshotted” case or creating the snapshot directory structure up-front.
return bus.NewMessage(bus.MessageID(time.Now().UnixNano()), &databasev1.Snapshot{
Name: sn,
Catalog: commonv1.Catalog_CATALOG_PROPERTY,
})
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
CHANGESlog.