github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb.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 bitree
    16  
    17  import (
    18  	"bytes"
    19  	"sync"
    20  
    21  	"github.com/zuoyebang/bitalosdb/bitpage"
    22  	"github.com/zuoyebang/bitalosdb/bitree/bdb"
    23  	"github.com/zuoyebang/bitalosdb/internal/consts"
    24  	"github.com/zuoyebang/bitalosdb/internal/options"
    25  	"github.com/zuoyebang/bitalosdb/internal/utils"
    26  )
    27  
    28  func (t *Bitree) openBdb(path string, opts *options.BdbOptions) error {
    29  	db, err := bdb.Open(path, opts)
    30  	if err != nil {
    31  		return err
    32  	}
    33  
    34  	var tx *bdb.Tx
    35  	tx, err = db.Begin(true)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	defer func() {
    40  		if err != nil {
    41  			_ = tx.Rollback()
    42  		}
    43  	}()
    44  
    45  	t.bdb = db
    46  	bucket := tx.Bucket(consts.BdbBucketName)
    47  	if bucket != nil {
    48  		_ = tx.Rollback()
    49  		return nil
    50  	}
    51  
    52  	bucket, err = tx.CreateBucket(consts.BdbBucketName)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	var pn bitpage.PageNum
    58  	pn, err = t.bpage.NewPage()
    59  	if err != nil {
    60  		return err
    61  	}
    62  	defer func() {
    63  		if err != nil {
    64  			_ = t.bpage.FreePage(pn, false)
    65  		}
    66  	}()
    67  
    68  	if err = bucket.Put(consts.BdbMaxKey, pn.ToByte()); err != nil {
    69  		return err
    70  	}
    71  
    72  	err = tx.Commit()
    73  	return err
    74  }
    75  
    76  func (t *Bitree) bdbSet(key, value []byte) error {
    77  	err := t.bdb.Update(func(tx *bdb.Tx) error {
    78  		bucket := tx.Bucket(consts.BdbBucketName)
    79  		if bucket == nil {
    80  			return bdb.ErrBucketNotFound
    81  		}
    82  		return bucket.Put(key, value)
    83  	})
    84  	return err
    85  }
    86  
    87  func (t *Bitree) bdbDelete(key []byte) error {
    88  	err := t.bdb.Update(func(tx *bdb.Tx) error {
    89  		bucket := tx.Bucket(consts.BdbBucketName)
    90  		if bucket == nil {
    91  			return bdb.ErrBucketNotFound
    92  		}
    93  		return bucket.Delete(key)
    94  	})
    95  	return err
    96  }
    97  
    98  func (t *Bitree) NewBdbIter() *bdb.BdbIterator {
    99  	rtx := t.txPool.Load()
   100  	return t.bdb.NewIter(rtx)
   101  }
   102  
   103  func (t *Bitree) FindKeyPageNum(key []byte) (bitpage.PageNum, []byte, func()) {
   104  	rtx := t.txPool.Load()
   105  	rtxCloser := func() {
   106  		rtx.Unref(true)
   107  	}
   108  
   109  	bkt := rtx.Bucket()
   110  	if bkt == nil {
   111  		t.opts.Logger.Errorf("FindKeyPageNum Bucket is nil index:%d", t.index)
   112  		return nilPageNum, nil, rtxCloser
   113  	}
   114  
   115  	pn, sentinel := t.findKeyPageNum(key, bkt.Cursor())
   116  	return pn, sentinel, rtxCloser
   117  }
   118  
   119  func (t *Bitree) findKeyPageNum(key []byte, cursor *bdb.Cursor) (bitpage.PageNum, []byte) {
   120  	sentinel, v := cursor.Seek(key)
   121  	if v == nil {
   122  		return nilPageNum, nil
   123  	}
   124  	return bitpage.PageNum(utils.BytesToUint32(v)), sentinel
   125  }
   126  
   127  func (t *Bitree) findPrefixDeleteKeyPageNums(
   128  	key []byte, cursor *bdb.Cursor,
   129  ) (pns []bitpage.PageNum, sentinels [][]byte) {
   130  	sentinel, v := cursor.Seek(key)
   131  	if v == nil {
   132  		return
   133  	}
   134  
   135  	sentinels = append(sentinels, sentinel)
   136  	pns = append(pns, bitpage.PageNum(utils.BytesToUint32(v)))
   137  
   138  	if bytes.Equal(sentinel, consts.BdbMaxKey) {
   139  		return
   140  	}
   141  
   142  	keyPrefixDelete := t.opts.KeyPrefixDeleteFunc(key)
   143  	if keyPrefixDelete != t.opts.KeyPrefixDeleteFunc(sentinel) {
   144  		return
   145  	}
   146  
   147  	for {
   148  		nk, nv := cursor.Next()
   149  		if nk == nil || nv == nil {
   150  			break
   151  		}
   152  
   153  		sentinels = append(sentinels, nk)
   154  		pns = append(pns, bitpage.PageNum(utils.BytesToUint32(nv)))
   155  
   156  		if bytes.Equal(sentinel, consts.BdbMaxKey) || keyPrefixDelete != t.opts.KeyPrefixDeleteFunc(nk) {
   157  			break
   158  		}
   159  	}
   160  
   161  	return
   162  }
   163  
   164  func (t *Bitree) BdbDiskSize() int64 {
   165  	return t.bdb.DiskSize()
   166  }
   167  
   168  func (t *Bitree) BdbPath() string {
   169  	return t.bdb.Path()
   170  }
   171  
   172  func (t *Bitree) BdbUpdate() bool {
   173  	_ = t.bdb.Update(func(tx *bdb.Tx) error { return nil })
   174  	return t.txPool.Update()
   175  }
   176  
   177  type TxPool struct {
   178  	lock sync.RWMutex
   179  	rTx  *bdb.ReadTx
   180  	bdb  *bdb.DB
   181  }
   182  
   183  func (t *Bitree) openTxPool() error {
   184  	if t.bdb == nil {
   185  		return ErrBdbNotExist
   186  	}
   187  
   188  	tx, err := t.bdb.Begin(false)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	bkt := tx.Bucket(consts.BdbBucketName)
   194  	if bkt == nil {
   195  		return ErrBucketNotExist
   196  	}
   197  
   198  	rt := &bdb.ReadTx{}
   199  	rt.Init(tx, bkt, t.bdb)
   200  	t.txPool = &TxPool{
   201  		rTx: rt,
   202  		bdb: t.bdb,
   203  	}
   204  
   205  	return nil
   206  }
   207  
   208  func (tp *TxPool) Load() *bdb.ReadTx {
   209  	tp.lock.RLock()
   210  	rTx := tp.rTx
   211  	rTx.Ref()
   212  	tp.lock.RUnlock()
   213  	return rTx
   214  }
   215  
   216  func (tp *TxPool) Update() bool {
   217  	tx, err := tp.bdb.Begin(false)
   218  	if err != nil {
   219  		return false
   220  	}
   221  
   222  	bkt := tx.Bucket(consts.BdbBucketName)
   223  	if bkt == nil {
   224  		return false
   225  	}
   226  
   227  	rt := &bdb.ReadTx{}
   228  	rt.Init(tx, bkt, tp.bdb)
   229  
   230  	tp.lock.Lock()
   231  	prev := tp.rTx
   232  	tp.rTx = rt
   233  	tp.lock.Unlock()
   234  
   235  	if prev != nil {
   236  		prev.Unref(true)
   237  	}
   238  
   239  	return true
   240  }
   241  
   242  func (tp *TxPool) Close() error {
   243  	tp.lock.RLock()
   244  	rTx := tp.rTx
   245  	tp.lock.RUnlock()
   246  	return rTx.Unref(false)
   247  }