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  }