github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/freelist_bitmap.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 "bytes" 19 "encoding/binary" 20 "fmt" 21 "unsafe" 22 23 "github.com/RoaringBitmap/roaring/roaring64" 24 ) 25 26 const ( 27 bitmapLenSize = 8 28 freelistLargeSize = 8 29 freelistBitmapHeaderSize = 16 30 ) 31 32 func (f *freelist) copyallBitmap(dst unsafe.Pointer, rb *roaring64.Bitmap, rbLen uint64) error { 33 bitmapLenBuf := unsafeByteSlice(dst, 0, 0, bitmapLenSize) 34 binary.LittleEndian.PutUint64(bitmapLenBuf, rbLen) 35 36 rbBytes, err := rb.ToBytes() 37 if err != nil { 38 return err 39 } 40 var c []byte 41 dst = unsafeAdd(dst, bitmapLenSize) 42 unsafeSlice(unsafe.Pointer(&c), dst, int(rbLen)) 43 copy(c, rbBytes) 44 return nil 45 } 46 47 func (f *freelist) readFromBitmap(p *page) { 48 if (p.flags & freelistPageFlag) == 0 { 49 panic(fmt.Sprintf("invalid freelist page: %d, page type is %s", p.id, p.typ())) 50 } 51 var idx, count = 0, int(p.count) 52 if count == 0xFFFF { 53 idx = 1 54 c := *(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))) 55 count = int(c) 56 if count < 0 { 57 panic(fmt.Sprintf("leading element count %d overflows int", c)) 58 } 59 } 60 61 if count == 0 { 62 f.ids = nil 63 } else { 64 var ids []pgid 65 var data unsafe.Pointer 66 data = unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx) 67 bitmapLenBuf := unsafeByteSlice(data, 0, 0, bitmapLenSize) 68 bitmapLen := binary.LittleEndian.Uint64(bitmapLenBuf) 69 70 data = unsafeAdd(data, bitmapLenSize) 71 bitmapData := unsafeByteSlice(data, 0, 0, int(bitmapLen)) 72 73 buf := new(bytes.Buffer) 74 buf.Write(bitmapData) 75 rb := roaring64.NewBitmap() 76 if _, err := rb.ReadFrom(buf); err != nil { 77 panic(fmt.Sprintf("read freelist from bitmap. err: %s", err)) 78 } 79 80 bitmapArray := rb.ToArray() 81 if len(bitmapArray) != count { 82 panic(fmt.Sprintf("read freelist count not match. page:%d, bitmap:%d", count, len(bitmapArray))) 83 } 84 idsCopy := *(*[]pgid)(unsafe.Pointer(&bitmapArray)) 85 86 f.readIDs(idsCopy) 87 } 88 } 89 90 func (f *freelist) writeBitmap(p *page, rb *roaring64.Bitmap, rbLen uint64, freeCount int) error { 91 p.flags |= freelistPageFlag 92 93 l := freeCount 94 if l == 0 { 95 p.count = uint16(l) 96 } else if l < 0xFFFF { 97 p.count = uint16(l) 98 data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) 99 return f.copyallBitmap(data, rb, rbLen) 100 } else { 101 p.count = 0xFFFF 102 data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) 103 pgidCount := unsafeByteSlice(data, 0, 0, freelistLargeSize) 104 binary.LittleEndian.PutUint64(pgidCount, uint64(l)) 105 data = unsafeAdd(data, freelistLargeSize) 106 return f.copyallBitmap(data, rb, rbLen) 107 } 108 109 return nil 110 }