github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/freelist.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 "fmt" 19 "sort" 20 "unsafe" 21 22 "github.com/RoaringBitmap/roaring/roaring64" 23 "github.com/zuoyebang/bitalosdb/internal/consts" 24 ) 25 26 type txPending struct { 27 ids []pgid 28 alloctx []txid 29 lastReleaseBegin txid 30 } 31 32 type pidSet map[pgid]struct{} 33 34 type freelist struct { 35 freelistType string 36 ids []pgid 37 allocs map[pgid]txid 38 pending map[txid]*txPending 39 cache map[pgid]bool 40 freemaps map[uint64]pidSet 41 forwardMap map[pgid]uint64 42 backwardMap map[pgid]uint64 43 allocate func(txid txid, n int) pgid 44 free_count func() int 45 mergeSpans func(ids pgids) 46 getFreePageIDs func() []pgid 47 readIDs func(pgids []pgid) 48 convertBitmap func() (rb *roaring64.Bitmap, count int) 49 } 50 51 func newFreelist(freelistType string) *freelist { 52 f := &freelist{ 53 freelistType: freelistType, 54 allocs: make(map[pgid]txid), 55 pending: make(map[txid]*txPending), 56 cache: make(map[pgid]bool), 57 freemaps: make(map[uint64]pidSet), 58 forwardMap: make(map[pgid]uint64), 59 backwardMap: make(map[pgid]uint64), 60 } 61 62 if freelistType == consts.BdbFreelistMapType { 63 f.allocate = f.hashmapAllocate 64 f.free_count = f.hashmapFreeCount 65 f.mergeSpans = f.hashmapMergeSpans 66 f.getFreePageIDs = f.hashmapGetFreePageIDs 67 f.readIDs = f.hashmapReadIDs 68 f.convertBitmap = f.hashmapConvertBitmap 69 } else { 70 f.allocate = f.arrayAllocate 71 f.free_count = f.arrayFreeCount 72 f.mergeSpans = f.arrayMergeSpans 73 f.getFreePageIDs = f.arrayGetFreePageIDs 74 f.readIDs = f.arrayReadIDs 75 f.convertBitmap = f.arrayConvertBitmap 76 } 77 78 return f 79 } 80 81 func (f *freelist) size() int { 82 n := f.count() 83 if n >= 0xFFFF { 84 n++ 85 } 86 return int(pageHeaderSize) + (int(unsafe.Sizeof(pgid(0))) * n) 87 } 88 89 func (f *freelist) count() int { 90 return f.free_count() + f.pending_count() 91 } 92 93 func (f *freelist) arrayFreeCount() int { 94 return len(f.ids) 95 } 96 97 func (f *freelist) pending_count() int { 98 var count int 99 for _, txp := range f.pending { 100 count += len(txp.ids) 101 } 102 return count 103 } 104 105 func (f *freelist) copyall(dst []pgid) { 106 m := make(pgids, 0, f.pending_count()) 107 for _, txp := range f.pending { 108 m = append(m, txp.ids...) 109 } 110 sort.Sort(m) 111 mergepgids(dst, f.getFreePageIDs(), m) 112 } 113 114 func (f *freelist) arrayAllocate(txid txid, n int) pgid { 115 if len(f.ids) == 0 { 116 return 0 117 } 118 119 var initial, previd pgid 120 for i, id := range f.ids { 121 if id <= 1 { 122 panic(fmt.Sprintf("invalid page allocation: %d", id)) 123 } 124 125 if previd == 0 || id-previd != 1 { 126 initial = id 127 } 128 129 if (id-initial)+1 == pgid(n) { 130 if (i + 1) == n { 131 f.ids = f.ids[i+1:] 132 } else { 133 copy(f.ids[i-n+1:], f.ids[i+1:]) 134 f.ids = f.ids[:len(f.ids)-n] 135 } 136 137 for i := pgid(0); i < pgid(n); i++ { 138 delete(f.cache, initial+i) 139 } 140 f.allocs[initial] = txid 141 return initial 142 } 143 144 previd = id 145 } 146 return 0 147 } 148 149 func (f *freelist) free(txid txid, p *page) { 150 if p.id <= 1 { 151 panic(fmt.Sprintf("cannot free page 0 or 1: %d", p.id)) 152 } 153 154 txp := f.pending[txid] 155 if txp == nil { 156 txp = &txPending{} 157 f.pending[txid] = txp 158 } 159 allocTxid, ok := f.allocs[p.id] 160 if ok { 161 delete(f.allocs, p.id) 162 } else if (p.flags & freelistPageFlag) != 0 { 163 allocTxid = txid - 1 164 } 165 166 for id := p.id; id <= p.id+pgid(p.overflow); id++ { 167 if f.cache[id] { 168 panic(fmt.Sprintf("page %d already freed", id)) 169 } 170 txp.ids = append(txp.ids, id) 171 txp.alloctx = append(txp.alloctx, allocTxid) 172 f.cache[id] = true 173 } 174 } 175 176 func (f *freelist) release(txid txid) pgids { 177 m := make(pgids, 0) 178 for tid, txp := range f.pending { 179 if tid <= txid { 180 m = append(m, txp.ids...) 181 delete(f.pending, tid) 182 } 183 } 184 f.mergeSpans(m) 185 return m 186 } 187 188 func (f *freelist) releaseRange(begin, end txid) pgids { 189 if begin > end { 190 return nil 191 } 192 var m pgids 193 for tid, txp := range f.pending { 194 if tid < begin || tid > end { 195 continue 196 } 197 if txp.lastReleaseBegin == begin { 198 continue 199 } 200 for i := 0; i < len(txp.ids); i++ { 201 if atx := txp.alloctx[i]; atx < begin || atx > end { 202 continue 203 } 204 m = append(m, txp.ids[i]) 205 txp.ids[i] = txp.ids[len(txp.ids)-1] 206 txp.ids = txp.ids[:len(txp.ids)-1] 207 txp.alloctx[i] = txp.alloctx[len(txp.alloctx)-1] 208 txp.alloctx = txp.alloctx[:len(txp.alloctx)-1] 209 i-- 210 } 211 txp.lastReleaseBegin = begin 212 if len(txp.ids) == 0 { 213 delete(f.pending, tid) 214 } 215 } 216 f.mergeSpans(m) 217 return m 218 } 219 220 func (f *freelist) rollback(txid txid) { 221 txp := f.pending[txid] 222 if txp == nil { 223 return 224 } 225 var m pgids 226 for i, pgid := range txp.ids { 227 delete(f.cache, pgid) 228 tx := txp.alloctx[i] 229 if tx == 0 { 230 continue 231 } 232 if tx != txid { 233 f.allocs[pgid] = tx 234 } else { 235 m = append(m, pgid) 236 } 237 } 238 239 delete(f.pending, txid) 240 f.mergeSpans(m) 241 } 242 243 func (f *freelist) freed(pgid pgid) bool { 244 return f.cache[pgid] 245 } 246 247 func (f *freelist) read(p *page) { 248 if (p.flags & freelistPageFlag) == 0 { 249 panic(fmt.Sprintf("invalid freelist page: %d, page type is %s", p.id, p.typ())) 250 } 251 var idx, count = 0, int(p.count) 252 if count == 0xFFFF { 253 idx = 1 254 c := *(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))) 255 count = int(c) 256 if count < 0 { 257 panic(fmt.Sprintf("leading element count %d overflows int", c)) 258 } 259 } 260 261 if count == 0 { 262 f.ids = nil 263 } else { 264 var ids []pgid 265 data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx) 266 unsafeSlice(unsafe.Pointer(&ids), data, count) 267 268 idsCopy := make([]pgid, count) 269 copy(idsCopy, ids) 270 sort.Sort(pgids(idsCopy)) 271 272 f.readIDs(idsCopy) 273 } 274 } 275 276 func (f *freelist) arrayReadIDs(ids []pgid) { 277 f.ids = ids 278 f.reindex() 279 } 280 281 func (f *freelist) arrayGetFreePageIDs() []pgid { 282 return f.ids 283 } 284 285 func (f *freelist) arrayConvertBitmap() (rb *roaring64.Bitmap, count int) { 286 rb = roaring64.NewBitmap() 287 for _, txp := range f.pending { 288 for _, id := range txp.ids { 289 rb.Add(uint64(id)) 290 count++ 291 } 292 } 293 for _, id := range f.ids { 294 rb.Add(uint64(id)) 295 count++ 296 } 297 298 return 299 } 300 301 func (f *freelist) write(p *page) error { 302 p.flags |= freelistPageFlag 303 l := f.count() 304 if l == 0 { 305 p.count = uint16(l) 306 } else if l < 0xFFFF { 307 p.count = uint16(l) 308 var ids []pgid 309 data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) 310 unsafeSlice(unsafe.Pointer(&ids), data, l) 311 f.copyall(ids) 312 } else { 313 p.count = 0xFFFF 314 var ids []pgid 315 data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) 316 unsafeSlice(unsafe.Pointer(&ids), data, l+1) 317 ids[0] = pgid(l) 318 f.copyall(ids[1:]) 319 } 320 321 return nil 322 } 323 324 func (f *freelist) reload(p *page, version uint32) { 325 if version == versionFreelistBitmap { 326 f.readFromBitmap(p) 327 } else { 328 f.read(p) 329 } 330 331 pcache := make(map[pgid]bool) 332 for _, txp := range f.pending { 333 for _, pendingID := range txp.ids { 334 pcache[pendingID] = true 335 } 336 } 337 338 var a []pgid 339 for _, id := range f.getFreePageIDs() { 340 if !pcache[id] { 341 a = append(a, id) 342 } 343 } 344 345 f.readIDs(a) 346 } 347 348 func (f *freelist) noSyncReload(pgids []pgid) { 349 pcache := make(map[pgid]bool) 350 for _, txp := range f.pending { 351 for _, pendingID := range txp.ids { 352 pcache[pendingID] = true 353 } 354 } 355 356 var a []pgid 357 for _, id := range pgids { 358 if !pcache[id] { 359 a = append(a, id) 360 } 361 } 362 363 f.readIDs(a) 364 } 365 366 func (f *freelist) reindex() { 367 ids := f.getFreePageIDs() 368 f.cache = make(map[pgid]bool, len(ids)) 369 for _, id := range ids { 370 f.cache[id] = true 371 } 372 for _, txp := range f.pending { 373 for _, pendingID := range txp.ids { 374 f.cache[pendingID] = true 375 } 376 } 377 } 378 379 func (f *freelist) arrayMergeSpans(ids pgids) { 380 sort.Sort(ids) 381 f.ids = pgids(f.ids).merge(ids) 382 }