github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/freelist_hmap.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  	"sort"
    19  
    20  	"github.com/RoaringBitmap/roaring/roaring64"
    21  )
    22  
    23  func (f *freelist) hashmapFreeCount() int {
    24  	count := 0
    25  	for _, size := range f.forwardMap {
    26  		count += int(size)
    27  	}
    28  	return count
    29  }
    30  
    31  func (f *freelist) hashmapAllocate(txid txid, n int) pgid {
    32  	if n == 0 {
    33  		return 0
    34  	}
    35  
    36  	if bm, ok := f.freemaps[uint64(n)]; ok {
    37  		for pid := range bm {
    38  			f.delSpan(pid, uint64(n))
    39  
    40  			f.allocs[pid] = txid
    41  
    42  			for i := pgid(0); i < pgid(n); i++ {
    43  				delete(f.cache, pid+i)
    44  			}
    45  			return pid
    46  		}
    47  	}
    48  
    49  	for size, bm := range f.freemaps {
    50  		if size < uint64(n) {
    51  			continue
    52  		}
    53  
    54  		for pid := range bm {
    55  			f.delSpan(pid, size)
    56  
    57  			f.allocs[pid] = txid
    58  
    59  			remain := size - uint64(n)
    60  
    61  			f.addSpan(pid+pgid(n), remain)
    62  
    63  			for i := pgid(0); i < pgid(n); i++ {
    64  				delete(f.cache, pid+i)
    65  			}
    66  			return pid
    67  		}
    68  	}
    69  
    70  	return 0
    71  }
    72  
    73  func (f *freelist) hashmapReadIDs(pgids []pgid) {
    74  	f.init(pgids)
    75  
    76  	f.reindex()
    77  }
    78  
    79  func (f *freelist) hashmapGetFreePageIDs() []pgid {
    80  	count := f.free_count()
    81  	if count == 0 {
    82  		return nil
    83  	}
    84  
    85  	m := make([]pgid, 0, count)
    86  	for start, size := range f.forwardMap {
    87  		for i := 0; i < int(size); i++ {
    88  			m = append(m, start+pgid(i))
    89  		}
    90  	}
    91  	sort.Sort(pgids(m))
    92  
    93  	return m
    94  }
    95  
    96  func (f *freelist) hashmapConvertBitmap() (rb *roaring64.Bitmap, count int) {
    97  	rb = roaring64.NewBitmap()
    98  	for _, txp := range f.pending {
    99  		for _, id := range txp.ids {
   100  			rb.Add(uint64(id))
   101  			count++
   102  		}
   103  	}
   104  
   105  	for start, size := range f.forwardMap {
   106  		for i := 0; i < int(size); i++ {
   107  			rb.Add(uint64(start + pgid(i)))
   108  			count++
   109  		}
   110  	}
   111  
   112  	return
   113  }
   114  
   115  func (f *freelist) hashmapMergeSpans(ids pgids) {
   116  	for _, id := range ids {
   117  		f.mergeWithExistingSpan(id)
   118  	}
   119  }
   120  
   121  func (f *freelist) mergeWithExistingSpan(pid pgid) {
   122  	prev := pid - 1
   123  	next := pid + 1
   124  
   125  	preSize, mergeWithPrev := f.backwardMap[prev]
   126  	nextSize, mergeWithNext := f.forwardMap[next]
   127  	newStart := pid
   128  	newSize := uint64(1)
   129  
   130  	if mergeWithPrev {
   131  		start := prev + 1 - pgid(preSize)
   132  		f.delSpan(start, preSize)
   133  
   134  		newStart -= pgid(preSize)
   135  		newSize += preSize
   136  	}
   137  
   138  	if mergeWithNext {
   139  		f.delSpan(next, nextSize)
   140  		newSize += nextSize
   141  	}
   142  
   143  	f.addSpan(newStart, newSize)
   144  }
   145  
   146  func (f *freelist) addSpan(start pgid, size uint64) {
   147  	f.backwardMap[start-1+pgid(size)] = size
   148  	f.forwardMap[start] = size
   149  	if _, ok := f.freemaps[size]; !ok {
   150  		f.freemaps[size] = make(map[pgid]struct{})
   151  	}
   152  
   153  	f.freemaps[size][start] = struct{}{}
   154  }
   155  
   156  func (f *freelist) delSpan(start pgid, size uint64) {
   157  	delete(f.forwardMap, start)
   158  	delete(f.backwardMap, start+pgid(size-1))
   159  	delete(f.freemaps[size], start)
   160  	if len(f.freemaps[size]) == 0 {
   161  		delete(f.freemaps, size)
   162  	}
   163  }
   164  
   165  func (f *freelist) init(pids []pgid) {
   166  	if len(pids) == 0 {
   167  		return
   168  	}
   169  
   170  	size := uint64(1)
   171  	start := pids[0]
   172  
   173  	if !sort.SliceIsSorted(pids, func(i, j int) bool { return pids[i] < pids[j] }) {
   174  		sort.Sort(pgids(pids))
   175  	}
   176  
   177  	f.freemaps = make(map[uint64]pidSet)
   178  	f.forwardMap = make(map[pgid]uint64)
   179  	f.backwardMap = make(map[pgid]uint64)
   180  
   181  	for i := 1; i < len(pids); i++ {
   182  		if pids[i] == pids[i-1]+1 {
   183  			size++
   184  		} else {
   185  			f.addSpan(start, size)
   186  
   187  			size = 1
   188  			start = pids[i]
   189  		}
   190  	}
   191  
   192  	if size != 0 && start != 0 {
   193  		f.addSpan(start, size)
   194  	}
   195  }