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 }