github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/freelist_hmap.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bdb 16 17 import ( 18 "sort" 19 20 "github.com/RoaringBitmap/roaring/roaring64" 21 ) 22 23 func (f *freelist) hashmapFreeCount() int { 24 count := 0 25 for _, size := range f.forwardMap { 26 count += int(size) 27 } 28 return count 29 } 30 31 func (f *freelist) hashmapAllocate(txid txid, n int) pgid { 32 if n == 0 { 33 return 0 34 } 35 36 if bm, ok := f.freemaps[uint64(n)]; ok { 37 for pid := range bm { 38 f.delSpan(pid, uint64(n)) 39 40 f.allocs[pid] = txid 41 42 for i := pgid(0); i < pgid(n); i++ { 43 delete(f.cache, pid+i) 44 } 45 return pid 46 } 47 } 48 49 for size, bm := range f.freemaps { 50 if size < uint64(n) { 51 continue 52 } 53 54 for pid := range bm { 55 f.delSpan(pid, size) 56 57 f.allocs[pid] = txid 58 59 remain := size - uint64(n) 60 61 f.addSpan(pid+pgid(n), remain) 62 63 for i := pgid(0); i < pgid(n); i++ { 64 delete(f.cache, pid+i) 65 } 66 return pid 67 } 68 } 69 70 return 0 71 } 72 73 func (f *freelist) hashmapReadIDs(pgids []pgid) { 74 f.init(pgids) 75 76 f.reindex() 77 } 78 79 func (f *freelist) hashmapGetFreePageIDs() []pgid { 80 count := f.free_count() 81 if count == 0 { 82 return nil 83 } 84 85 m := make([]pgid, 0, count) 86 for start, size := range f.forwardMap { 87 for i := 0; i < int(size); i++ { 88 m = append(m, start+pgid(i)) 89 } 90 } 91 sort.Sort(pgids(m)) 92 93 return m 94 } 95 96 func (f *freelist) hashmapConvertBitmap() (rb *roaring64.Bitmap, count int) { 97 rb = roaring64.NewBitmap() 98 for _, txp := range f.pending { 99 for _, id := range txp.ids { 100 rb.Add(uint64(id)) 101 count++ 102 } 103 } 104 105 for start, size := range f.forwardMap { 106 for i := 0; i < int(size); i++ { 107 rb.Add(uint64(start + pgid(i))) 108 count++ 109 } 110 } 111 112 return 113 } 114 115 func (f *freelist) hashmapMergeSpans(ids pgids) { 116 for _, id := range ids { 117 f.mergeWithExistingSpan(id) 118 } 119 } 120 121 func (f *freelist) mergeWithExistingSpan(pid pgid) { 122 prev := pid - 1 123 next := pid + 1 124 125 preSize, mergeWithPrev := f.backwardMap[prev] 126 nextSize, mergeWithNext := f.forwardMap[next] 127 newStart := pid 128 newSize := uint64(1) 129 130 if mergeWithPrev { 131 start := prev + 1 - pgid(preSize) 132 f.delSpan(start, preSize) 133 134 newStart -= pgid(preSize) 135 newSize += preSize 136 } 137 138 if mergeWithNext { 139 f.delSpan(next, nextSize) 140 newSize += nextSize 141 } 142 143 f.addSpan(newStart, newSize) 144 } 145 146 func (f *freelist) addSpan(start pgid, size uint64) { 147 f.backwardMap[start-1+pgid(size)] = size 148 f.forwardMap[start] = size 149 if _, ok := f.freemaps[size]; !ok { 150 f.freemaps[size] = make(map[pgid]struct{}) 151 } 152 153 f.freemaps[size][start] = struct{}{} 154 } 155 156 func (f *freelist) delSpan(start pgid, size uint64) { 157 delete(f.forwardMap, start) 158 delete(f.backwardMap, start+pgid(size-1)) 159 delete(f.freemaps[size], start) 160 if len(f.freemaps[size]) == 0 { 161 delete(f.freemaps, size) 162 } 163 } 164 165 func (f *freelist) init(pids []pgid) { 166 if len(pids) == 0 { 167 return 168 } 169 170 size := uint64(1) 171 start := pids[0] 172 173 if !sort.SliceIsSorted(pids, func(i, j int) bool { return pids[i] < pids[j] }) { 174 sort.Sort(pgids(pids)) 175 } 176 177 f.freemaps = make(map[uint64]pidSet) 178 f.forwardMap = make(map[pgid]uint64) 179 f.backwardMap = make(map[pgid]uint64) 180 181 for i := 1; i < len(pids); i++ { 182 if pids[i] == pids[i-1]+1 { 183 size++ 184 } else { 185 f.addSpan(start, size) 186 187 size = 1 188 start = pids[i] 189 } 190 } 191 192 if size != 0 && start != 0 { 193 f.addSpan(start, size) 194 } 195 }