|
- package bbolt
-
- import "sort"
-
- // hashmapFreeCount returns count of free pages(hashmap version)
- func (f *freelist) hashmapFreeCount() int {
- // use the forwardmap to get the total count
- count := 0
- for _, size := range f.forwardMap {
- count += int(size)
- }
- return count
- }
-
- // hashmapAllocate serves the same purpose as arrayAllocate, but use hashmap as backend
- func (f *freelist) hashmapAllocate(txid txid, n int) pgid {
- if n == 0 {
- return 0
- }
-
- // if we have a exact size match just return short path
- if bm, ok := f.freemaps[uint64(n)]; ok {
- for pid := range bm {
- // remove the span
- f.delSpan(pid, uint64(n))
-
- f.allocs[pid] = txid
-
- for i := pgid(0); i < pgid(n); i++ {
- delete(f.cache, pid+pgid(i))
- }
- return pid
- }
- }
-
- // lookup the map to find larger span
- for size, bm := range f.freemaps {
- if size < uint64(n) {
- continue
- }
-
- for pid := range bm {
- // remove the initial
- f.delSpan(pid, uint64(size))
-
- f.allocs[pid] = txid
-
- remain := size - uint64(n)
-
- // add remain span
- f.addSpan(pid+pgid(n), remain)
-
- for i := pgid(0); i < pgid(n); i++ {
- delete(f.cache, pid+pgid(i))
- }
- return pid
- }
- }
-
- return 0
- }
-
- // hashmapReadIDs reads pgids as input an initial the freelist(hashmap version)
- func (f *freelist) hashmapReadIDs(pgids []pgid) {
- f.init(pgids)
-
- // Rebuild the page cache.
- f.reindex()
- }
-
- // hashmapGetFreePageIDs returns the sorted free page ids
- func (f *freelist) hashmapGetFreePageIDs() []pgid {
- count := f.free_count()
- if count == 0 {
- return nil
- }
-
- m := make([]pgid, 0, count)
- for start, size := range f.forwardMap {
- for i := 0; i < int(size); i++ {
- m = append(m, start+pgid(i))
- }
- }
- sort.Sort(pgids(m))
-
- return m
- }
-
- // hashmapMergeSpans try to merge list of pages(represented by pgids) with existing spans
- func (f *freelist) hashmapMergeSpans(ids pgids) {
- for _, id := range ids {
- // try to see if we can merge and update
- f.mergeWithExistingSpan(id)
- }
- }
-
- // mergeWithExistingSpan merges pid to the existing free spans, try to merge it backward and forward
- func (f *freelist) mergeWithExistingSpan(pid pgid) {
- prev := pid - 1
- next := pid + 1
-
- preSize, mergeWithPrev := f.backwardMap[prev]
- nextSize, mergeWithNext := f.forwardMap[next]
- newStart := pid
- newSize := uint64(1)
-
- if mergeWithPrev {
- //merge with previous span
- start := prev + 1 - pgid(preSize)
- f.delSpan(start, preSize)
-
- newStart -= pgid(preSize)
- newSize += preSize
- }
-
- if mergeWithNext {
- // merge with next span
- f.delSpan(next, nextSize)
- newSize += nextSize
- }
-
- f.addSpan(newStart, newSize)
- }
-
- func (f *freelist) addSpan(start pgid, size uint64) {
- f.backwardMap[start-1+pgid(size)] = size
- f.forwardMap[start] = size
- if _, ok := f.freemaps[size]; !ok {
- f.freemaps[size] = make(map[pgid]struct{})
- }
-
- f.freemaps[size][start] = struct{}{}
- }
-
- func (f *freelist) delSpan(start pgid, size uint64) {
- delete(f.forwardMap, start)
- delete(f.backwardMap, start+pgid(size-1))
- delete(f.freemaps[size], start)
- if len(f.freemaps[size]) == 0 {
- delete(f.freemaps, size)
- }
- }
-
- // initial from pgids using when use hashmap version
- // pgids must be sorted
- func (f *freelist) init(pgids []pgid) {
- if len(pgids) == 0 {
- return
- }
-
- size := uint64(1)
- start := pgids[0]
-
- if !sort.SliceIsSorted([]pgid(pgids), func(i, j int) bool { return pgids[i] < pgids[j] }) {
- panic("pgids not sorted")
- }
-
- f.freemaps = make(map[uint64]pidSet)
- f.forwardMap = make(map[pgid]uint64)
- f.backwardMap = make(map[pgid]uint64)
-
- for i := 1; i < len(pgids); i++ {
- // continuous page
- if pgids[i] == pgids[i-1]+1 {
- size++
- } else {
- f.addSpan(start, size)
-
- size = 1
- start = pgids[i]
- }
- }
-
- // init the tail
- if size != 0 && start != 0 {
- f.addSpan(start, size)
- }
- }
|