github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/page.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 bitpage
    16  
    17  import (
    18  	"bytes"
    19  	"sync"
    20  	"sync/atomic"
    21  
    22  	"github.com/zuoyebang/bitalosdb/internal/consts"
    23  	"github.com/zuoyebang/bitalosdb/internal/invariants"
    24  	"github.com/zuoyebang/bitalosdb/internal/utils"
    25  )
    26  
    27  const (
    28  	pageFlushStateNone uint32 = iota
    29  	pageFlushStateSendTask
    30  	pageFlushStateStart
    31  	pageFlushStateFinish
    32  )
    33  
    34  const (
    35  	pageSplitStateNone uint8 = iota
    36  	pageSplitStateSendTask
    37  	pageSplitStateStart
    38  	pageSplitStateFinish
    39  )
    40  
    41  type page struct {
    42  	bp         *Bitpage
    43  	pn         PageNum
    44  	dirname    string
    45  	maxKey     []byte
    46  	flushState atomic.Uint32
    47  
    48  	mu struct {
    49  		sync.RWMutex
    50  		stMutable *superTable
    51  		stQueue   flushableList
    52  		arrtable  *flushableEntry
    53  	}
    54  
    55  	readState struct {
    56  		sync.RWMutex
    57  		val *readState
    58  	}
    59  }
    60  
    61  func newPage(bp *Bitpage, pn PageNum) *page {
    62  	return &page{
    63  		bp:      bp,
    64  		dirname: bp.dirname,
    65  		pn:      pn,
    66  	}
    67  }
    68  
    69  func (p *page) openFiles(pm *pagemetaItem, files []fileInfo) error {
    70  	var deleteFiles []string
    71  
    72  	addDeleteFile := func(name string) {
    73  		if utils.IsFileNotExist(name) {
    74  			return
    75  		}
    76  		deleteFiles = append(deleteFiles, name)
    77  	}
    78  
    79  	for _, f := range files {
    80  		switch f.ft {
    81  		case fileTypeSuperTable:
    82  			if f.fn >= pm.nextStFileNum || f.fn < pm.minUnflushedStFileNum {
    83  				addDeleteFile(f.path)
    84  			} else if err := p.newSuperTable(f.path, f.fn, true); err != nil {
    85  				return err
    86  			}
    87  		case fileTypeArrayTable:
    88  			if f.fn == pm.curAtFileNum {
    89  				_, atEntry, err := p.newArrayTable(f.path, f.fn, true)
    90  				if err != nil {
    91  					return err
    92  				}
    93  				p.mu.arrtable = atEntry
    94  			} else {
    95  				addDeleteFile(f.path)
    96  			}
    97  		}
    98  	}
    99  
   100  	if len(deleteFiles) > 0 {
   101  		p.bp.opts.DeleteFilePacer.AddFiles(deleteFiles)
   102  	}
   103  
   104  	p.updateReadState()
   105  
   106  	return nil
   107  }
   108  
   109  func (p *page) makeMutableForWrite(flushIdx bool) error {
   110  	st := p.mu.stMutable
   111  	if st != nil {
   112  		if st.empty() {
   113  			return nil
   114  		}
   115  
   116  		if flushIdx {
   117  			if err := st.writeIdxToFile(); err != nil {
   118  				return err
   119  			}
   120  		}
   121  	}
   122  
   123  	fn := p.bp.meta.getNextStFileNum(p.pn)
   124  	path := p.bp.makeFilePath(fileTypeSuperTable, p.pn, fn)
   125  	if err := p.newSuperTable(path, fn, false); err != nil {
   126  		return err
   127  	}
   128  
   129  	p.updateReadState()
   130  	return nil
   131  }
   132  
   133  func (p *page) newSklTable(path string, fn FileNum, exist bool) error {
   134  	st, err := newSklTable(path, exist, p.bp)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	invariants.SetFinalizer(st, checkSklTable)
   140  
   141  	entry := p.newFlushableEntry(st, fn)
   142  	entry.release = func() {
   143  		if err := st.close(); err != nil {
   144  			p.bp.opts.Logger.Errorf("bitpage close sklTable fail file:%s err:%s", path, err.Error())
   145  		}
   146  
   147  		if entry.obsolete {
   148  			p.deleteObsoleteFile(path)
   149  		}
   150  	}
   151  
   152  	p.mu.stQueue = append(p.mu.stQueue, entry)
   153  	return nil
   154  }
   155  
   156  func (p *page) newSuperTable(path string, fn FileNum, exist bool) error {
   157  	st, err := newSuperTable(p, path, fn, exist)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	invariants.SetFinalizer(st, checkSuperTable)
   163  
   164  	idxPath := st.getIdxFilePath()
   165  	entry := p.newFlushableEntry(st, fn)
   166  	entry.release = func() {
   167  		if entry.obsolete {
   168  			st.indexModified = false
   169  		}
   170  
   171  		if err := st.close(); err != nil {
   172  			p.bp.opts.Logger.Errorf("bitpage close superTable fail file:%s err:%s", path, err.Error())
   173  		}
   174  
   175  		if entry.obsolete {
   176  			p.deleteObsoleteFile(path)
   177  			p.deleteObsoleteFile(idxPath)
   178  		}
   179  	}
   180  
   181  	p.mu.stMutable = st
   182  	p.mu.stQueue = append(p.mu.stQueue, entry)
   183  
   184  	return nil
   185  }
   186  
   187  func (p *page) newArrayTable(path string, fn FileNum, exist bool) (*arrayTable, *flushableEntry, error) {
   188  	var err error
   189  	var at *arrayTable
   190  
   191  	cacheOpts := atCacheOptions{
   192  		cache: p.bp.cache,
   193  		id:    (uint64(p.pn) << 32) | uint64(fn),
   194  	}
   195  
   196  	if exist {
   197  		at, err = openArrayTable(path, &cacheOpts)
   198  	} else {
   199  		opts := atOptions{
   200  			useMapIndex:       p.bp.opts.UseMapIndex,
   201  			usePrefixCompress: p.bp.opts.UsePrefixCompress,
   202  			useBlockCompress:  p.bp.opts.UseBlockCompress,
   203  			blockSize:         consts.BitpageBlockSize,
   204  		}
   205  		at, err = newArrayTable(path, &opts, &cacheOpts)
   206  	}
   207  	if err != nil {
   208  		return nil, nil, err
   209  	}
   210  
   211  	invariants.SetFinalizer(at, checkArrayTable)
   212  
   213  	entry := p.newFlushableEntry(at, fn)
   214  	entry.release = func() {
   215  		if err := at.close(); err != nil {
   216  			p.bp.opts.Logger.Errorf("bitpage close arrayTable fail file:%s err:%s", path, err.Error())
   217  		}
   218  
   219  		if entry.obsolete {
   220  			p.deleteObsoleteFile(path)
   221  		}
   222  	}
   223  
   224  	return at, entry, nil
   225  }
   226  
   227  func (p *page) newFlushableEntry(f flushable, fn FileNum) *flushableEntry {
   228  	entry := &flushableEntry{
   229  		flushable: f,
   230  		fileNum:   fn,
   231  		obsolete:  false,
   232  	}
   233  	entry.readerRefs.Store(1)
   234  	return entry
   235  }
   236  
   237  func (p *page) getFilesPath() []string {
   238  	var paths []string
   239  	for _, st := range p.mu.stQueue {
   240  		paths = append(paths, st.path())
   241  		idxFile := st.idxFilePath()
   242  		if utils.IsFileExist(idxFile) {
   243  			paths = append(paths, idxFile)
   244  		}
   245  	}
   246  	if p.mu.arrtable != nil {
   247  		paths = append(paths, p.mu.arrtable.path())
   248  	}
   249  	return paths
   250  }
   251  
   252  func (p *page) close(delete bool) error {
   253  	p.mu.Lock()
   254  	defer p.mu.Unlock()
   255  
   256  	p.readState.Lock()
   257  	if p.readState.val != nil {
   258  		p.readState.val.unref()
   259  	}
   260  	p.readState.Unlock()
   261  
   262  	for i := range p.mu.stQueue {
   263  		if delete {
   264  			p.mu.stQueue[i].setObsolete()
   265  		}
   266  		p.mu.stQueue[i].readerUnref()
   267  	}
   268  
   269  	if p.mu.arrtable != nil {
   270  		if delete {
   271  			p.mu.arrtable.setObsolete()
   272  		}
   273  		p.mu.arrtable.readerUnref()
   274  	}
   275  
   276  	return nil
   277  }
   278  
   279  func (p *page) inuseStState() (int, uint64, int, float64) {
   280  	p.mu.RLock()
   281  	defer p.mu.RUnlock()
   282  
   283  	var itemCount int
   284  	var size uint64
   285  	var delPercent float64
   286  	for i := range p.mu.stQueue {
   287  		itemCount += p.mu.stQueue[i].itemCount()
   288  		size += p.mu.stQueue[i].inuseBytes()
   289  		dp := p.mu.stQueue[i].delPercent()
   290  		if delPercent < dp {
   291  			delPercent = dp
   292  		}
   293  	}
   294  
   295  	return itemCount, size, len(p.mu.stQueue), delPercent
   296  }
   297  
   298  func (p *page) loadReadState() (*readState, func()) {
   299  	p.readState.RLock()
   300  	state := p.readState.val
   301  	state.stMutable.mmapRLock()
   302  	state.ref()
   303  	p.readState.RUnlock()
   304  	return state, func() {
   305  		state.stMutable.mmapRUnLock()
   306  		state.unref()
   307  	}
   308  }
   309  
   310  func (p *page) updateReadState() {
   311  	s := &readState{
   312  		stMutable: p.mu.stMutable,
   313  		stQueue:   p.mu.stQueue,
   314  		arrtable:  p.mu.arrtable,
   315  	}
   316  	s.refcnt.Store(1)
   317  
   318  	for i := range s.stQueue {
   319  		s.stQueue[i].readerRef()
   320  	}
   321  
   322  	if s.arrtable != nil {
   323  		s.arrtable.readerRef()
   324  	}
   325  
   326  	p.readState.Lock()
   327  	old := p.readState.val
   328  	p.readState.val = s
   329  	p.readState.Unlock()
   330  
   331  	if old != nil {
   332  		old.unref()
   333  	}
   334  }
   335  
   336  func (p *page) get(key []byte, khash uint32) ([]byte, bool, func(), internalKeyKind) {
   337  	rs, rsCloser := p.loadReadState()
   338  
   339  	stIndex := len(rs.stQueue) - 1
   340  	for stIndex >= 0 {
   341  		st := rs.stQueue[stIndex]
   342  		val, exist, kind, _ := st.get(key, khash)
   343  		if exist {
   344  			switch kind {
   345  			case internalKeyKindSet, internalKeyKindPrefixDelete:
   346  				return val, true, rsCloser, kind
   347  			case internalKeyKindDelete:
   348  				rsCloser()
   349  				return nil, false, nil, kind
   350  			}
   351  		}
   352  
   353  		stIndex--
   354  	}
   355  
   356  	if rs.arrtable != nil {
   357  		val, exist, _, atCloser := rs.arrtable.get(key, khash)
   358  		if exist {
   359  			closer := func() {
   360  				rsCloser()
   361  				if atCloser != nil {
   362  					atCloser()
   363  				}
   364  			}
   365  			return val, true, closer, internalKeyKindSet
   366  		}
   367  	}
   368  
   369  	rsCloser()
   370  	return nil, false, nil, internalKeyKindInvalid
   371  }
   372  
   373  func (p *page) newIter(o *iterOptions) *PageIterator {
   374  	rs, rsCloser := p.loadReadState()
   375  
   376  	buf := pageIterAllocPool.Get().(*pageIterAlloc)
   377  	dbi := &buf.dbi
   378  	*dbi = PageIterator{
   379  		alloc:               buf,
   380  		cmp:                 bytes.Compare,
   381  		equal:               bytes.Equal,
   382  		readState:           rs,
   383  		readStateCloser:     rsCloser,
   384  		iter:                &buf.merging,
   385  		key:                 &buf.key,
   386  		keyBuf:              buf.keyBuf,
   387  		prefixOrFullSeekKey: buf.prefixOrFullSeekKey,
   388  	}
   389  	if o != nil {
   390  		dbi.opts = *o
   391  	}
   392  	dbi.opts.Logger = p.bp.opts.Logger
   393  
   394  	sts := rs.stQueue
   395  	mlevels := buf.mlevels[:0]
   396  	numMergingLevels := len(sts)
   397  	if rs.arrtable != nil {
   398  		numMergingLevels++
   399  	}
   400  	if numMergingLevels > cap(mlevels) {
   401  		mlevels = make([]mergingIterLevel, 0, numMergingLevels)
   402  	}
   403  
   404  	for i := len(sts) - 1; i >= 0; i-- {
   405  		mlevels = append(mlevels, mergingIterLevel{
   406  			iter: sts[i].newIter(&dbi.opts),
   407  		})
   408  	}
   409  
   410  	if rs.arrtable != nil {
   411  		mlevels = append(mlevels, mergingIterLevel{
   412  			iter: rs.arrtable.newIter(&dbi.opts),
   413  		})
   414  	}
   415  
   416  	buf.merging.Init(&dbi.opts, dbi.cmp, mlevels...)
   417  	return dbi
   418  }
   419  
   420  func (p *page) set(key internalKey, value []byte) error {
   421  	p.mu.RLock()
   422  	st := p.mu.stMutable
   423  	p.mu.RUnlock()
   424  
   425  	st.kindStatis(key.Kind())
   426  	return st.set(key, value)
   427  }
   428  
   429  func (p *page) deleteObsoleteFile(filename string) {
   430  	if utils.IsFileNotExist(filename) {
   431  		return
   432  	}
   433  
   434  	p.bp.opts.DeleteFilePacer.AddFile(filename)
   435  }
   436  
   437  func (p *page) canSendFlushTask() bool {
   438  	return p.getFlushState() == pageFlushStateNone
   439  }
   440  
   441  func (p *page) canFlush() bool {
   442  	return p.getFlushState() == pageFlushStateSendTask
   443  }
   444  
   445  func (p *page) getFlushState() uint32 {
   446  	return p.flushState.Load()
   447  }
   448  
   449  func (p *page) setFlushState(v uint32) {
   450  	p.flushState.Store(v)
   451  }
   452  
   453  func (p *page) maybeScheduleFlush(flushSize uint64, isForce bool) bool {
   454  	if !p.canSendFlushTask() {
   455  		return false
   456  	}
   457  
   458  	if isForce {
   459  		p.setFlushState(pageFlushStateSendTask)
   460  		return true
   461  	}
   462  
   463  	itemCount, stSize, stNum, delPercent := p.inuseStState()
   464  	if stSize > flushSize ||
   465  		stNum > 1 ||
   466  		consts.CheckFlushDelPercent(delPercent, stSize, flushSize) ||
   467  		consts.CheckFlushItemCount(itemCount, stSize, flushSize) {
   468  		p.bp.opts.Logger.Infof("[BITPAGE %d] push flush task pn:%s flushSize:%d stSize:%d stNum:%d delPercent:%.2f itemCount:%d",
   469  			p.bp.index, p.pn, flushSize, stSize, stNum, delPercent, itemCount)
   470  		p.setFlushState(pageFlushStateSendTask)
   471  		return true
   472  	}
   473  
   474  	return false
   475  }
   476  
   477  func (p *page) memFlushFinish() error {
   478  	p.mu.RLock()
   479  	st := p.mu.stMutable
   480  	p.mu.RUnlock()
   481  	return st.mergeIndexes()
   482  }