Skip to content

Commit

Permalink
Add verification on mergeSpans
Browse files Browse the repository at this point in the history
There shouldn't have any duplicated free page IDs, or overlap
between the new free page IDs and the existing free page IDs.

Signed-off-by: Benjamin Wang <[email protected]>
  • Loading branch information
ahrtr committed Jun 21, 2024
1 parent 7b66ea8 commit a792979
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
24 changes: 24 additions & 0 deletions freelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,5 +389,29 @@ func (f *freelist) reindex() {
// arrayMergeSpans try to merge list of pages(represented by pgids) with existing spans but using array
func (f *freelist) arrayMergeSpans(ids common.Pgids) {
sort.Sort(ids)
common.Verify(func() {
idsIdx := make(map[common.Pgid]struct{})
for _, id := range f.ids {
// The existing f.ids shouldn't have duplicated free ID.
if _, ok := idsIdx[id]; ok {
panic(fmt.Sprintf("detected duplicated free page ID: %d in existing f.ids: %v", id, f.ids))
}
idsIdx[id] = struct{}{}
}

prev := common.Pgid(0)
for _, id := range ids {
// The ids shouldn't have duplicated free ID.
if prev == id {
panic(fmt.Sprintf("detected duplicated free ID: %d in ids: %v", id, ids))
}
prev = id

// The ids shouldn't have any overlap with the existing f.ids.
if _, ok := idsIdx[id]; ok {
panic(fmt.Sprintf("detected overlapped free page ID: %d between ids: %v and existing f.ids: %v", id, ids, f.ids))
}
}
})
f.ids = common.Pgids(f.ids).Merge(ids)
}
79 changes: 79 additions & 0 deletions freelist_hmap.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package bbolt

import (
"fmt"
"reflect"
"sort"

"go.etcd.io/bbolt/internal/common"
Expand Down Expand Up @@ -108,6 +110,33 @@ func (f *freelist) hashmapGetFreePageIDs() []common.Pgid {

// hashmapMergeSpans try to merge list of pages(represented by pgids) with existing spans
func (f *freelist) hashmapMergeSpans(ids common.Pgids) {
common.Verify(func() {
ids1 := f.idsFromFreemaps()
ids2 := f.idsFromForwardMap()
ids3 := f.idsFromBackwardMap()

if !reflect.DeepEqual(ids1, ids2) {
panic(fmt.Sprintf("Detected mismatch, f.freemaps: %v, f.forwardMap: %v", f.freemaps, f.forwardMap))
}
if !reflect.DeepEqual(ids1, ids3) {
panic(fmt.Sprintf("Detected mismatch, f.freemaps: %v, f.backwardMap: %v", f.freemaps, f.backwardMap))
}

sort.Sort(ids)
prev := common.Pgid(0)
for _, id := range ids {
// The ids shouldn't have duplicated free ID.
if prev == id {
panic(fmt.Sprintf("detected duplicated free ID: %d in ids: %v", id, ids))
}
prev = id

// The ids shouldn't have any overlap with the existing f.freemaps.
if _, ok := ids1[id]; ok {
panic(fmt.Sprintf("detected overlapped free page ID: %d between ids: %v and existing f.freemaps: %v", id, ids, f.freemaps))
}
}
})
for _, id := range ids {
// try to see if we can merge and update
f.mergeWithExistingSpan(id)
Expand Down Expand Up @@ -200,3 +229,53 @@ func (f *freelist) init(pgids []common.Pgid) {
f.addSpan(start, size)
}
}

// idsFromFreemaps get all free page IDs from f.freemaps.
// used by test only.
func (f *freelist) idsFromFreemaps() map[common.Pgid]struct{} {
ids := make(map[common.Pgid]struct{})
for size, idSet := range f.freemaps {
for start := range idSet {
for i := 0; i < int(size); i++ {
id := start + common.Pgid(i)
if _, ok := ids[id]; ok {
panic(fmt.Sprintf("detected duplicated free page ID: %d in f.freemaps: %v", id, f.freemaps))
}
ids[id] = struct{}{}
}
}
}
return ids
}

// idsFromForwardMap get all free page IDs from f.forwardMap.
// used by test only.
func (f *freelist) idsFromForwardMap() map[common.Pgid]struct{} {
ids := make(map[common.Pgid]struct{})
for start, size := range f.forwardMap {
for i := 0; i < int(size); i++ {
id := start + common.Pgid(i)
if _, ok := ids[id]; ok {
panic(fmt.Sprintf("detected duplicated free page ID: %d in f.forwardMap: %v", id, f.forwardMap))
}
ids[id] = struct{}{}
}
}
return ids
}

// idsFromBackwardMap get all free page IDs from f.backwardMap.
// used by test only.
func (f *freelist) idsFromBackwardMap() map[common.Pgid]struct{} {
ids := make(map[common.Pgid]struct{})
for end, size := range f.backwardMap {
for i := 0; i < int(size); i++ {
id := end - common.Pgid(i)
if _, ok := ids[id]; ok {
panic(fmt.Sprintf("detected duplicated free page ID: %d in f.backwardMap: %v", id, f.backwardMap))
}
ids[id] = struct{}{}
}
}
return ids
}

0 comments on commit a792979

Please sign in to comment.