github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/page.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  	"os"
    20  	"sort"
    21  	"unsafe"
    22  
    23  	"github.com/cockroachdb/errors"
    24  )
    25  
    26  const pageHeaderSize = unsafe.Sizeof(page{})
    27  
    28  const minKeysPerPage = 2
    29  
    30  const branchPageElementSize = unsafe.Sizeof(branchPageElement{})
    31  const leafPageElementSize = unsafe.Sizeof(leafPageElement{})
    32  
    33  const (
    34  	branchPageFlag   = 0x01
    35  	leafPageFlag     = 0x02
    36  	metaPageFlag     = 0x04
    37  	freelistPageFlag = 0x10
    38  )
    39  
    40  const (
    41  	bucketLeafFlag = 0x01
    42  )
    43  
    44  type pgid uint64
    45  
    46  type page struct {
    47  	id       pgid
    48  	flags    uint16
    49  	count    uint16
    50  	overflow uint32
    51  }
    52  
    53  func (p *page) typ() string {
    54  	if (p.flags & branchPageFlag) != 0 {
    55  		return "branch"
    56  	} else if (p.flags & leafPageFlag) != 0 {
    57  		return "leaf"
    58  	} else if (p.flags & metaPageFlag) != 0 {
    59  		return "meta"
    60  	} else if (p.flags & freelistPageFlag) != 0 {
    61  		return "freelist"
    62  	}
    63  	return fmt.Sprintf("unknown<%02x>", p.flags)
    64  }
    65  
    66  func (p *page) meta() *meta {
    67  	return (*meta)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))
    68  }
    69  
    70  func (p *page) leafPageElement(index uint16) *leafPageElement {
    71  	return (*leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
    72  		leafPageElementSize, int(index)))
    73  }
    74  
    75  func (p *page) leafPageElements() []leafPageElement {
    76  	if p.count == 0 {
    77  		return nil
    78  	}
    79  	var elems []leafPageElement
    80  	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
    81  	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
    82  	return elems
    83  }
    84  
    85  func (p *page) branchPageElement(index uint16) *branchPageElement {
    86  	return (*branchPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),
    87  		unsafe.Sizeof(branchPageElement{}), int(index)))
    88  }
    89  
    90  func (p *page) branchPageElements() []branchPageElement {
    91  	if p.count == 0 {
    92  		return nil
    93  	}
    94  	var elems []branchPageElement
    95  	data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))
    96  	unsafeSlice(unsafe.Pointer(&elems), data, int(p.count))
    97  	return elems
    98  }
    99  
   100  func (p *page) hexdump(n int) {
   101  	buf := unsafeByteSlice(unsafe.Pointer(p), 0, 0, n)
   102  	fmt.Fprintf(os.Stderr, "%x\n", buf)
   103  }
   104  
   105  type pages []*page
   106  
   107  func (s pages) Len() int           { return len(s) }
   108  func (s pages) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   109  func (s pages) Less(i, j int) bool { return s[i].id < s[j].id }
   110  
   111  type branchPageElement struct {
   112  	pos   uint32
   113  	ksize uint32
   114  	pgid  pgid
   115  }
   116  
   117  func (n *branchPageElement) key() []byte {
   118  	return unsafeByteSlice(unsafe.Pointer(n), 0, int(n.pos), int(n.pos)+int(n.ksize))
   119  }
   120  
   121  type leafPageElement struct {
   122  	flags uint32
   123  	pos   uint32
   124  	ksize uint32
   125  	vsize uint32
   126  }
   127  
   128  func (n *leafPageElement) key() []byte {
   129  	i := int(n.pos)
   130  	j := i + int(n.ksize)
   131  	return unsafeByteSlice(unsafe.Pointer(n), 0, i, j)
   132  }
   133  
   134  func (n *leafPageElement) value() []byte {
   135  	i := int(n.pos) + int(n.ksize)
   136  	j := i + int(n.vsize)
   137  	return unsafeByteSlice(unsafe.Pointer(n), 0, i, j)
   138  }
   139  
   140  type PageInfo struct {
   141  	ID            int
   142  	Type          string
   143  	Count         int
   144  	OverflowCount int
   145  }
   146  
   147  type pgids []pgid
   148  
   149  func (s pgids) Len() int           { return len(s) }
   150  func (s pgids) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   151  func (s pgids) Less(i, j int) bool { return s[i] < s[j] }
   152  
   153  func (a pgids) merge(b pgids) pgids {
   154  	if len(a) == 0 {
   155  		return b
   156  	}
   157  	if len(b) == 0 {
   158  		return a
   159  	}
   160  	merged := make(pgids, len(a)+len(b))
   161  	mergepgids(merged, a, b)
   162  	return merged
   163  }
   164  
   165  func mergepgids(dst, a, b pgids) {
   166  	if len(dst) < len(a)+len(b) {
   167  		panic(errors.Errorf("mergepgids bad len %d < %d + %d", len(dst), len(a), len(b)))
   168  	}
   169  
   170  	if len(a) == 0 {
   171  		copy(dst, b)
   172  		return
   173  	}
   174  	if len(b) == 0 {
   175  		copy(dst, a)
   176  		return
   177  	}
   178  
   179  	merged := dst[:0]
   180  
   181  	lead, follow := a, b
   182  	if b[0] < a[0] {
   183  		lead, follow = b, a
   184  	}
   185  
   186  	for len(lead) > 0 {
   187  		n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] })
   188  		merged = append(merged, lead[:n]...)
   189  		if n >= len(lead) {
   190  			break
   191  		}
   192  
   193  		lead, follow = follow, lead[n:]
   194  	}
   195  
   196  	_ = append(merged, follow...)
   197  }