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  }