mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-25 03:22:36 +00:00 
			
		
		
		
	* update bleve to master b17287a86f6cac923a5d886e10618df994eeb54b6724eac2e3b8dde89cfbe3a2 * remove unused pkg from dep file * change bleve from master to recent revision
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package bbolt
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"sort"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
 | |
| 
 | |
| const minKeysPerPage = 2
 | |
| 
 | |
| const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
 | |
| const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
 | |
| 
 | |
| const (
 | |
| 	branchPageFlag   = 0x01
 | |
| 	leafPageFlag     = 0x02
 | |
| 	metaPageFlag     = 0x04
 | |
| 	freelistPageFlag = 0x10
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	bucketLeafFlag = 0x01
 | |
| )
 | |
| 
 | |
| type pgid uint64
 | |
| 
 | |
| type page struct {
 | |
| 	id       pgid
 | |
| 	flags    uint16
 | |
| 	count    uint16
 | |
| 	overflow uint32
 | |
| 	ptr      uintptr
 | |
| }
 | |
| 
 | |
| // typ returns a human readable page type string used for debugging.
 | |
| func (p *page) typ() string {
 | |
| 	if (p.flags & branchPageFlag) != 0 {
 | |
| 		return "branch"
 | |
| 	} else if (p.flags & leafPageFlag) != 0 {
 | |
| 		return "leaf"
 | |
| 	} else if (p.flags & metaPageFlag) != 0 {
 | |
| 		return "meta"
 | |
| 	} else if (p.flags & freelistPageFlag) != 0 {
 | |
| 		return "freelist"
 | |
| 	}
 | |
| 	return fmt.Sprintf("unknown<%02x>", p.flags)
 | |
| }
 | |
| 
 | |
| // meta returns a pointer to the metadata section of the page.
 | |
| func (p *page) meta() *meta {
 | |
| 	return (*meta)(unsafe.Pointer(&p.ptr))
 | |
| }
 | |
| 
 | |
| // leafPageElement retrieves the leaf node by index
 | |
| func (p *page) leafPageElement(index uint16) *leafPageElement {
 | |
| 	n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
 | |
| 	return n
 | |
| }
 | |
| 
 | |
| // leafPageElements retrieves a list of leaf nodes.
 | |
| func (p *page) leafPageElements() []leafPageElement {
 | |
| 	if p.count == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
 | |
| }
 | |
| 
 | |
| // branchPageElement retrieves the branch node by index
 | |
| func (p *page) branchPageElement(index uint16) *branchPageElement {
 | |
| 	return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index]
 | |
| }
 | |
| 
 | |
| // branchPageElements retrieves a list of branch nodes.
 | |
| func (p *page) branchPageElements() []branchPageElement {
 | |
| 	if p.count == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
 | |
| }
 | |
| 
 | |
| // dump writes n bytes of the page to STDERR as hex output.
 | |
| func (p *page) hexdump(n int) {
 | |
| 	buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:n]
 | |
| 	fmt.Fprintf(os.Stderr, "%x\n", buf)
 | |
| }
 | |
| 
 | |
| type pages []*page
 | |
| 
 | |
| func (s pages) Len() int           { return len(s) }
 | |
| func (s pages) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 | |
| func (s pages) Less(i, j int) bool { return s[i].id < s[j].id }
 | |
| 
 | |
| // branchPageElement represents a node on a branch page.
 | |
| type branchPageElement struct {
 | |
| 	pos   uint32
 | |
| 	ksize uint32
 | |
| 	pgid  pgid
 | |
| }
 | |
| 
 | |
| // key returns a byte slice of the node key.
 | |
| func (n *branchPageElement) key() []byte {
 | |
| 	buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
 | |
| 	return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize]
 | |
| }
 | |
| 
 | |
| // leafPageElement represents a node on a leaf page.
 | |
| type leafPageElement struct {
 | |
| 	flags uint32
 | |
| 	pos   uint32
 | |
| 	ksize uint32
 | |
| 	vsize uint32
 | |
| }
 | |
| 
 | |
| // key returns a byte slice of the node key.
 | |
| func (n *leafPageElement) key() []byte {
 | |
| 	buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
 | |
| 	return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
 | |
| }
 | |
| 
 | |
| // value returns a byte slice of the node value.
 | |
| func (n *leafPageElement) value() []byte {
 | |
| 	buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
 | |
| 	return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
 | |
| }
 | |
| 
 | |
| // PageInfo represents human readable information about a page.
 | |
| type PageInfo struct {
 | |
| 	ID            int
 | |
| 	Type          string
 | |
| 	Count         int
 | |
| 	OverflowCount int
 | |
| }
 | |
| 
 | |
| type pgids []pgid
 | |
| 
 | |
| func (s pgids) Len() int           { return len(s) }
 | |
| func (s pgids) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 | |
| func (s pgids) Less(i, j int) bool { return s[i] < s[j] }
 | |
| 
 | |
| // merge returns the sorted union of a and b.
 | |
| func (a pgids) merge(b pgids) pgids {
 | |
| 	// Return the opposite slice if one is nil.
 | |
| 	if len(a) == 0 {
 | |
| 		return b
 | |
| 	}
 | |
| 	if len(b) == 0 {
 | |
| 		return a
 | |
| 	}
 | |
| 	merged := make(pgids, len(a)+len(b))
 | |
| 	mergepgids(merged, a, b)
 | |
| 	return merged
 | |
| }
 | |
| 
 | |
| // mergepgids copies the sorted union of a and b into dst.
 | |
| // If dst is too small, it panics.
 | |
| func mergepgids(dst, a, b pgids) {
 | |
| 	if len(dst) < len(a)+len(b) {
 | |
| 		panic(fmt.Errorf("mergepgids bad len %d < %d + %d", len(dst), len(a), len(b)))
 | |
| 	}
 | |
| 	// Copy in the opposite slice if one is nil.
 | |
| 	if len(a) == 0 {
 | |
| 		copy(dst, b)
 | |
| 		return
 | |
| 	}
 | |
| 	if len(b) == 0 {
 | |
| 		copy(dst, a)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Merged will hold all elements from both lists.
 | |
| 	merged := dst[:0]
 | |
| 
 | |
| 	// Assign lead to the slice with a lower starting value, follow to the higher value.
 | |
| 	lead, follow := a, b
 | |
| 	if b[0] < a[0] {
 | |
| 		lead, follow = b, a
 | |
| 	}
 | |
| 
 | |
| 	// Continue while there are elements in the lead.
 | |
| 	for len(lead) > 0 {
 | |
| 		// Merge largest prefix of lead that is ahead of follow[0].
 | |
| 		n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] })
 | |
| 		merged = append(merged, lead[:n]...)
 | |
| 		if n >= len(lead) {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		// Swap lead and follow.
 | |
| 		lead, follow = follow, lead[n:]
 | |
| 	}
 | |
| 
 | |
| 	// Append what's left in follow.
 | |
| 	_ = append(merged, follow...)
 | |
| }
 |