github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bithash/bithash.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 bithash 16 17 import ( 18 "sync" 19 20 "github.com/zuoyebang/bitalosdb/internal/base" 21 "github.com/zuoyebang/bitalosdb/internal/compress" 22 "github.com/zuoyebang/bitalosdb/internal/list2" 23 "github.com/zuoyebang/bitalosdb/internal/options" 24 "github.com/zuoyebang/bitalosdb/internal/utils" 25 "github.com/zuoyebang/bitalosdb/internal/vfs" 26 ) 27 28 type FS vfs.FS 29 type File vfs.File 30 31 type Bithash struct { 32 meta *BithashMetadata 33 fs FS 34 index int 35 logger base.Logger 36 compressor compress.Compressor 37 dirname string 38 tableMaxSize int 39 bhtReaders sync.Map 40 rwwWriters sync.Map 41 tLock sync.Mutex 42 stats *Stats 43 cLogWriter *compactLogWriter 44 cLogUpdate bool 45 closeTableWg sync.WaitGroup 46 deleteFilePacer *base.DeletionFileLimiter 47 bytesPerSync int 48 49 mufn struct { 50 sync.RWMutex 51 fnMap map[FileNum]FileNum 52 } 53 54 mutw struct { 55 sync.Mutex 56 mutableWriters *list2.Stack 57 } 58 } 59 60 func Open(dirname string, opts *options.BithashOptions) (b *Bithash, err error) { 61 b = &Bithash{ 62 dirname: dirname, 63 fs: opts.FS, 64 tableMaxSize: opts.TableMaxSize, 65 logger: opts.Logger, 66 compressor: opts.Compressor, 67 index: opts.Index, 68 deleteFilePacer: opts.DeleteFilePacer, 69 bytesPerSync: opts.BytesPerSync, 70 bhtReaders: sync.Map{}, 71 rwwWriters: sync.Map{}, 72 stats: &Stats{}, 73 } 74 75 if err = b.fs.MkdirAll(dirname, 0755); err != nil { 76 return nil, err 77 } 78 79 b.mufn.fnMap = make(map[FileNum]FileNum, 1<<10) 80 b.mutw.mutableWriters = list2.NewStack() 81 82 if err = initManifest(b); err != nil { 83 return nil, err 84 } 85 86 if err = b.initTables(); err != nil { 87 return nil, err 88 } 89 90 if err = initFileNumMap(b); err != nil { 91 return nil, err 92 } 93 94 return b, nil 95 } 96 97 func (b *Bithash) TableMaxSize() int64 { 98 return int64(b.tableMaxSize) 99 } 100 101 func (b *Bithash) Get(key []byte, khash uint32, fn FileNum) (value []byte, putPool func(), err error) { 102 if rwwWriter, ok := b.rwwWriters.Load(fn); ok { 103 value, putPool, err = rwwWriter.(*Writer).Get(key, khash) 104 if err == nil && value != nil { 105 return 106 } 107 } 108 109 fileNum := b.GetFileNumMap(fn) 110 if fileNum == FileNum(0) { 111 return nil, nil, ErrBhFileNumZero 112 } 113 114 if bhtReader, ok := b.bhtReaders.Load(fileNum); ok { 115 return bhtReader.(*Reader).Get(key, khash) 116 } 117 118 return nil, nil, ErrBhNotFound 119 } 120 121 func (b *Bithash) FlushStart() (*BithashWriter, error) { 122 return b.NewBithashWriter(false) 123 } 124 125 func (b *Bithash) FlushFinish(wr *BithashWriter) error { 126 if wr == nil { 127 return nil 128 } 129 return wr.Finish() 130 } 131 132 func (b *Bithash) Delete(fn FileNum) error { 133 fileNum := b.GetFileNumMap(fn) 134 if fileNum == FileNum(0) { 135 fileNum = fn 136 } 137 138 b.stats.DelKeyTotal.Add(1) 139 b.meta.updateFileDelKeyNum(fileNum, 1) 140 return nil 141 } 142 143 func (b *Bithash) Close() (err error) { 144 if b.meta != nil { 145 if err = b.meta.close(); err != nil { 146 b.logger.Errorf("bithash[%s] close meta fail err:%s", b.dirname, err) 147 } 148 } 149 150 if b.cLogWriter != nil { 151 if err = b.cLogWriter.close(); err != nil { 152 b.logger.Errorf("bithash[%s] close compactLog fail err:%s", b.dirname, err) 153 } 154 } 155 156 b.rwwWriters.Range(func(fn, w interface{}) bool { 157 err = w.(*Writer).Close() 158 return true 159 }) 160 161 b.bhtReaders.Range(func(fn, r interface{}) bool { 162 err = r.(*Reader).Close() 163 return true 164 }) 165 166 b.closeTableWg.Wait() 167 168 return 169 } 170 171 func (b *Bithash) RemoveTableFiles(fileNums []FileNum) { 172 var deleteFiles []string 173 for _, fileNum := range fileNums { 174 b.deleteReaders(fileNum) 175 b.meta.freeFileMetadata(fileNum) 176 filename := MakeFilepath(b.fs, b.dirname, fileTypeTable, fileNum) 177 if utils.IsFileNotExist(filename) { 178 b.logger.Errorf("bithash RemoveTableFiles not exist file:%s", filename) 179 continue 180 } 181 182 deleteFiles = append(deleteFiles, filename) 183 } 184 185 if len(deleteFiles) > 0 { 186 b.deleteFilePacer.AddFiles(deleteFiles) 187 b.stats.FileTotal.Add(^uint32(len(deleteFiles) - 1)) 188 } 189 } 190 191 func (b *Bithash) closeMutableWriters() (err error) { 192 b.mutw.Lock() 193 defer b.mutw.Unlock() 194 195 for !b.mutw.mutableWriters.Empty() { 196 w := b.mutw.mutableWriters.Pop() 197 if w == nil { 198 continue 199 } 200 if err = b.closeTable(w.(*Writer), true); err != nil { 201 return err 202 } 203 } 204 205 return nil 206 } 207 208 func (b *Bithash) popMutableWriters() *Writer { 209 b.mutw.Lock() 210 bhWriter := b.mutw.mutableWriters.Pop() 211 b.mutw.Unlock() 212 213 if bhWriter == nil { 214 return nil 215 } 216 217 return bhWriter.(*Writer) 218 } 219 220 func (b *Bithash) pushMutableWriters(wr *Writer) { 221 b.mutw.Lock() 222 b.mutw.mutableWriters.Push(wr) 223 b.mutw.Unlock() 224 return 225 } 226 227 func (b *Bithash) emptyMutableWriters() bool { 228 b.mutw.Lock() 229 isEmpty := b.mutw.mutableWriters.Empty() 230 b.mutw.Unlock() 231 return isEmpty 232 } 233 234 func (b *Bithash) addReaders(r *Reader) { 235 b.bhtReaders.Store(r.fileNum, r) 236 } 237 238 func (b *Bithash) deleteReaders(fn FileNum) { 239 b.bhtReaders.Delete(fn) 240 } 241 242 func (b *Bithash) addRwwWriters(w *Writer) { 243 b.rwwWriters.Store(w.fileNum, w) 244 } 245 246 func (b *Bithash) deleteRwwWriters(fn FileNum) { 247 b.rwwWriters.Delete(fn) 248 } 249 250 func (b *Bithash) SetFileNumMap(dst FileNum, src FileNum) { 251 b.mufn.Lock() 252 b.mufn.fnMap[src] = dst 253 _ = b.cLogWriter.writeRecord(compactLogKindSet, src, dst) 254 b.mufn.Unlock() 255 } 256 257 func (b *Bithash) DeleteFileNumMap(fn FileNum) { 258 b.mufn.Lock() 259 delete(b.mufn.fnMap, fn) 260 _ = b.cLogWriter.writeRecord(compactLogKindDelete, fn, fn) 261 b.mufn.Unlock() 262 } 263 264 func (b *Bithash) GetFileNumMap(src FileNum) (dst FileNum) { 265 b.mufn.RLock() 266 if val, ok := b.mufn.fnMap[src]; ok { 267 dst = val 268 } else { 269 dst = FileNum(0) 270 } 271 b.mufn.RUnlock() 272 return 273 } 274 275 func (b *Bithash) NewBithashWriter(compact bool) (*BithashWriter, error) { 276 bhWriter := &BithashWriter{ 277 b: b, 278 compact: compact, 279 } 280 281 if !compact && !b.emptyMutableWriters() { 282 mutableWriter := b.popMutableWriters() 283 if mutableWriter != nil { 284 bhWriter.wr = mutableWriter 285 return bhWriter, nil 286 } 287 } 288 289 writer, err := NewTableWriter(b, compact) 290 if err != nil { 291 return nil, err 292 } 293 294 bhWriter.wr = writer 295 return bhWriter, nil 296 }