github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/writer.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 "encoding/binary" 19 20 "github.com/cockroachdb/errors" 21 "github.com/zuoyebang/bitalosdb/bithash" 22 "github.com/zuoyebang/bitalosdb/bitpage" 23 "github.com/zuoyebang/bitalosdb/bitree/bdb" 24 "github.com/zuoyebang/bitalosdb/internal/base" 25 "github.com/zuoyebang/bitalosdb/internal/bitask" 26 ) 27 28 type BitreeWriter struct { 29 btree *Bitree 30 bdbReadTx *bdb.ReadTx 31 bdbCursor *bdb.Cursor 32 bhashWriter *bithash.BithashWriter 33 bpageWriter map[bitpage.PageNum]*bitpage.PageWriter 34 } 35 36 func (w *BitreeWriter) getBitpageWriter(pn bitpage.PageNum, sentinel []byte) *bitpage.PageWriter { 37 pageWriter, ok := w.bpageWriter[pn] 38 if ok { 39 return pageWriter 40 } 41 42 writer := w.btree.bpage.GetPageWriter(pn, sentinel) 43 if writer == nil { 44 return nil 45 } 46 47 w.bpageWriter[pn] = writer 48 return writer 49 } 50 51 func (w *BitreeWriter) set(key base.InternalKey, value []byte, pn bitpage.PageNum, sentinel []byte) (err error) { 52 pageWriter := w.getBitpageWriter(pn, sentinel) 53 if pageWriter == nil { 54 return errors.Errorf("bitree: getBitpageWriter nil index:%d pageNum:%s", w.btree.index, pn) 55 } 56 57 switch key.Kind() { 58 case base.InternalKeyKindSet: 59 keySeqNum := key.SeqNum() 60 if w.btree.IsKvSeparate(len(value)) { 61 keyFileNum, err := w.bhashWriter.Add(key, value) 62 if err != nil { 63 return err 64 } 65 66 isExistTm, tm := w.btree.opts.KvTimestampFunc(value, 1) 67 if isExistTm { 68 var ev [20]byte 69 binary.LittleEndian.PutUint64(ev[0:8], (keySeqNum<<8)|uint64(base.InternalKeyKindSetBithash)) 70 binary.LittleEndian.PutUint32(ev[8:12], uint32(keyFileNum)) 71 binary.LittleEndian.PutUint64(ev[12:20], tm) 72 err = pageWriter.Set(key, ev[:]) 73 } else { 74 var ev [12]byte 75 binary.LittleEndian.PutUint64(ev[0:8], (keySeqNum<<8)|uint64(base.InternalKeyKindSetBithash)) 76 binary.LittleEndian.PutUint32(ev[8:12], uint32(keyFileNum)) 77 err = pageWriter.Set(key, ev[:]) 78 } 79 } else { 80 ev, evCloser := base.EncodeInternalValue(value, keySeqNum, base.InternalKeyKindSet) 81 err = pageWriter.Set(key, ev) 82 evCloser() 83 } 84 case base.InternalKeyKindDelete, base.InternalKeyKindPrefixDelete: 85 err = pageWriter.Set(key, nil) 86 } 87 88 return err 89 } 90 91 func (w *BitreeWriter) Apply(key base.InternalKey, value []byte) error { 92 kind := key.Kind() 93 if kind != base.InternalKeyKindPrefixDelete { 94 pn, sentinel := w.btree.findKeyPageNum(key.UserKey, w.bdbCursor) 95 if pn == nilPageNum { 96 return errors.New("findKeyPageNum nil") 97 } 98 99 if err := w.set(key, value, pn, sentinel); err != nil { 100 return err 101 } 102 } else { 103 pns, sentinels := w.btree.findPrefixDeleteKeyPageNums(key.UserKey, w.bdbCursor) 104 if len(pns) == 0 || len(sentinels) == 0 { 105 return errors.New("findPrefixDeleteKeyPageNums nil") 106 } 107 108 for j := range pns { 109 if err := w.set(key, value, pns[j], sentinels[j]); err != nil { 110 continue 111 } 112 } 113 } 114 115 return nil 116 } 117 118 func (w *BitreeWriter) RefBdbTx() { 119 if w.bdbReadTx == nil { 120 w.bdbReadTx = w.btree.txPool.Load() 121 w.bdbCursor = w.bdbReadTx.Bucket().Cursor() 122 } 123 } 124 125 func (w *BitreeWriter) UnrefBdbTx() { 126 if w.bdbReadTx != nil { 127 w.bdbReadTx.Unref(true) 128 w.bdbReadTx = nil 129 } 130 } 131 132 func (w *BitreeWriter) Finish() error { 133 w.UnrefBdbTx() 134 135 if w.bhashWriter != nil { 136 if err := w.btree.bhash.FlushFinish(w.bhashWriter); err != nil { 137 return err 138 } 139 w.bhashWriter = nil 140 } 141 142 flushSize := w.btree.opts.BitpageFlushSize 143 144 for pn, pageWriter := range w.bpageWriter { 145 if err := pageWriter.FlushFinish(); err != nil { 146 w.btree.opts.Logger.Errorf("bitree pageWriter FlushFinish fail pn:%d err:%s", pn, err) 147 continue 148 } 149 pageWriter.UpdateMetaTimestamp() 150 if pageWriter.MaybePageFlush(flushSize) { 151 w.btree.opts.BitpageTaskPushFunc(&bitask.BitpageTaskData{ 152 Index: w.btree.index, 153 Event: bitask.BitpageEventFlush, 154 Pn: uint32(pn), 155 Sentinel: pageWriter.Sentinel, 156 }) 157 } 158 } 159 160 w.bpageWriter = nil 161 return nil 162 } 163 164 func (t *Bitree) NewBitreeWriter() (*BitreeWriter, error) { 165 writer := &BitreeWriter{ 166 btree: t, 167 } 168 169 if t.opts.UseBithash { 170 w, err := t.bhash.FlushStart() 171 if err != nil { 172 return nil, err 173 } 174 writer.bhashWriter = w 175 } 176 177 writer.RefBdbTx() 178 writer.bpageWriter = make(map[bitpage.PageNum]*bitpage.PageWriter, 16) 179 180 return writer, nil 181 }