github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/bitpage.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  	"arena"
    19  	"encoding/binary"
    20  	"errors"
    21  	"fmt"
    22  	"sort"
    23  	"sync"
    24  
    25  	"github.com/zuoyebang/bitalosdb/internal/base"
    26  	"github.com/zuoyebang/bitalosdb/internal/cache/lrucache"
    27  	"github.com/zuoyebang/bitalosdb/internal/consts"
    28  	"github.com/zuoyebang/bitalosdb/internal/options"
    29  	"github.com/zuoyebang/bitalosdb/internal/statemachine"
    30  	"github.com/zuoyebang/bitalosdb/internal/utils"
    31  	"github.com/zuoyebang/bitalosdb/internal/vfs"
    32  )
    33  
    34  type FS vfs.FS
    35  type File vfs.File
    36  
    37  var (
    38  	ErrPageNotFound    = errors.New("page not exist")
    39  	ErrPageSplitted    = errors.New("page splitted")
    40  	ErrPageNotSplitted = errors.New("page not splitted")
    41  	ErrPageFlushState  = errors.New("page flush state err")
    42  	ErrTableFull       = errors.New("allocation failed because table is full")
    43  	ErrTableSize       = errors.New("tbl size is not large enough to hold the header")
    44  	ErrTableOpenType   = errors.New("tbl open type not support")
    45  )
    46  
    47  type Bitpage struct {
    48  	meta          *bitpagemeta
    49  	opts          *options.BitpageOptions
    50  	pages         sync.Map
    51  	pageWriters   sync.Map
    52  	splittedPages sync.Map
    53  	dirname       string
    54  	index         int
    55  	stats         *Stats
    56  	dbState       *statemachine.DbStateMachine
    57  	cache         *lrucache.LruCache
    58  	stArena       *arena.Arena
    59  	stArenaBuf    []byte
    60  }
    61  
    62  type SplitPageInfo struct {
    63  	Pn       PageNum
    64  	IsEmpty  bool
    65  	Sentinel []byte
    66  }
    67  
    68  type PageDebugInfo struct {
    69  	Ct         int64
    70  	Ut         int64
    71  	SplitState uint8
    72  }
    73  
    74  type fileInfo struct {
    75  	ft   FileType
    76  	fn   FileNum
    77  	path string
    78  }
    79  
    80  func Open(dirname string, opts *options.BitpageOptions) (b *Bitpage, err error) {
    81  	b = &Bitpage{
    82  		dirname:       dirname,
    83  		opts:          opts,
    84  		pages:         sync.Map{},
    85  		pageWriters:   sync.Map{},
    86  		splittedPages: sync.Map{},
    87  		index:         opts.Index,
    88  		stats:         newStats(),
    89  		dbState:       opts.DbState,
    90  		cache:         nil,
    91  	}
    92  
    93  	if err = b.opts.FS.MkdirAll(dirname, 0755); err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	if err = openManifest(b); err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	if b.opts.UseBlockCompress {
   102  		cacheOpts := &options.CacheOptions{
   103  			Size:     b.opts.BitpageBlockCacheSize,
   104  			Shards:   consts.BitpageBlockCacheShards,
   105  			HashSize: consts.BitpageBlockCacheHashSize,
   106  			Logger:   b.opts.Logger,
   107  		}
   108  		b.cache = lrucache.NewLrucache(cacheOpts)
   109  		b.opts.Logger.Infof("bitpage new block cache ok index:%d size:%d", opts.Index, cacheOpts.Size)
   110  	}
   111  
   112  	defer b.freeStArenaBuf()
   113  
   114  	if err = b.openPages(); err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	return b, nil
   119  }
   120  
   121  func (b *Bitpage) openPages() error {
   122  	files, err := b.opts.FS.List(b.dirname)
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	if len(files) == 0 {
   128  		return nil
   129  	}
   130  
   131  	sort.Strings(files)
   132  
   133  	pageFiles := make(map[PageNum][]fileInfo, 1<<10)
   134  	for i := range files {
   135  		ft, pn, fn, ok := parseFilename(files[i])
   136  		if !ok || ft == fileTypeManifest {
   137  			continue
   138  		}
   139  
   140  		if _, exist := pageFiles[pn]; !exist {
   141  			b.SetPage(pn, newPage(b, pn))
   142  		}
   143  
   144  		pageFiles[pn] = append(pageFiles[pn], fileInfo{
   145  			ft:   ft,
   146  			fn:   fn,
   147  			path: b.opts.FS.PathJoin(b.dirname, files[i]),
   148  		})
   149  	}
   150  
   151  	for pageNum, pm := range b.meta.mu.pagemetaMap {
   152  		p := b.GetPage(pageNum)
   153  		if p == nil {
   154  			p = newPage(b, pageNum)
   155  			b.SetPage(pageNum, p)
   156  		} else if err = p.openFiles(pm, pageFiles[pageNum]); err != nil {
   157  			return err
   158  		}
   159  
   160  		if b.PageSplitted(pageNum) {
   161  			if err = b.FreePage(pageNum, false); err != nil {
   162  				b.opts.Logger.Errorf("bitpage freePage fail index:%d pn:%s err:%s", b.index, pageNum, err.Error())
   163  			}
   164  		} else {
   165  			b.setPageNoneSplit(pageNum)
   166  			if p.mu.stMutable == nil {
   167  				if err = p.makeMutableForWrite(false); err != nil {
   168  					return err
   169  				}
   170  			}
   171  		}
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  func (b *Bitpage) NewPage() (PageNum, error) {
   178  	p, err := b.newPageInternal()
   179  	if err != nil {
   180  		return PageNum(0), nil
   181  	}
   182  	return p.pn, nil
   183  }
   184  
   185  func (b *Bitpage) newPageInternal() (*page, error) {
   186  	pn := b.meta.getNextPageNum()
   187  	b.meta.newPagemetaItem(pn)
   188  	p := newPage(b, pn)
   189  	if err := p.makeMutableForWrite(false); err != nil {
   190  		b.meta.freePagemetaItem(pn)
   191  		return nil, err
   192  	}
   193  
   194  	b.SetPage(pn, p)
   195  	return p, nil
   196  }
   197  
   198  func (b *Bitpage) FreePage(pn PageNum, checked bool) error {
   199  	p := b.GetPage(pn)
   200  	if p == nil {
   201  		return ErrPageNotFound
   202  	}
   203  
   204  	if checked && !b.PageSplitted(pn) {
   205  		return ErrPageNotSplitted
   206  	}
   207  
   208  	if err := p.close(true); err != nil {
   209  		return err
   210  	}
   211  
   212  	b.pages.Delete(pn)
   213  	b.pageWriters.Delete(pn)
   214  	b.splittedPages.Delete(pn)
   215  	b.meta.freePagemetaItem(p.pn)
   216  
   217  	return nil
   218  }
   219  
   220  func (b *Bitpage) GetPageDebugInfo(pn PageNum) PageDebugInfo {
   221  	pinfo := PageDebugInfo{}
   222  	pm := b.meta.getPagemetaItem(pn)
   223  	if pm != nil {
   224  		pinfo.Ct = int64(pm.createTimestamp)
   225  		pinfo.Ut = int64(pm.updateTimestamp)
   226  		pinfo.SplitState = pm.splitState
   227  	}
   228  
   229  	return pinfo
   230  }
   231  
   232  func (b *Bitpage) GetPage(pn PageNum) *page {
   233  	p, ok := b.pages.Load(pn)
   234  	if !ok {
   235  		return nil
   236  	}
   237  
   238  	return p.(*page)
   239  }
   240  
   241  func (b *Bitpage) SetPage(pn PageNum, p *page) {
   242  	b.pages.Store(pn, p)
   243  }
   244  
   245  func (b *Bitpage) GetCacheMetrics() string {
   246  	if b.cache == nil {
   247  		return ""
   248  	}
   249  	return b.cache.MetricsInfo()
   250  }
   251  
   252  func (b *Bitpage) GetPageDelPercent(pn PageNum) float64 {
   253  	p := b.GetPage(pn)
   254  	if p == nil {
   255  		return 0
   256  	}
   257  	_, _, _, delPercent := p.inuseStState()
   258  	return delPercent
   259  }
   260  
   261  func (b *Bitpage) pageNoneSplit(pn PageNum) bool {
   262  	return b.meta.getSplitState(pn) == pageSplitStateNone
   263  }
   264  
   265  func (b *Bitpage) setPageNoneSplit(pn PageNum) {
   266  	b.meta.setSplitState(pn, pageSplitStateNone)
   267  }
   268  
   269  func (b *Bitpage) PageSplitted(pn PageNum) bool {
   270  	return b.meta.getSplitState(pn) == pageSplitStateFinish
   271  }
   272  
   273  func (b *Bitpage) PageSplitted2(pn PageNum) bool {
   274  	_, ok := b.splittedPages.Load(pn)
   275  	return ok
   276  }
   277  
   278  func (b *Bitpage) MarkFreePages(pns []PageNum) {
   279  	for i := range pns {
   280  		if b.GetPage(pns[i]) == nil {
   281  			continue
   282  		}
   283  		b.markFreePage(pns[i])
   284  	}
   285  }
   286  
   287  func (b *Bitpage) markFreePage(pn PageNum) {
   288  	b.splittedPages.Store(pn, true)
   289  	b.meta.setSplitState(pn, pageSplitStateFinish)
   290  }
   291  
   292  func (b *Bitpage) CheckFreePages(except PageNum) bool {
   293  	isAllFree := true
   294  	b.pages.Range(func(pn, p interface{}) bool {
   295  		if pn == except {
   296  			return true
   297  		}
   298  
   299  		if b.PageSplitted(pn.(PageNum)) {
   300  			return true
   301  		}
   302  
   303  		isAllFree = false
   304  		return false
   305  	})
   306  
   307  	return isAllFree
   308  }
   309  
   310  func (b *Bitpage) Get(pn PageNum, key []byte, khash uint32) ([]byte, bool, func(), base.InternalKeyKind) {
   311  	p := b.GetPage(pn)
   312  	if p == nil {
   313  		return nil, false, nil, internalKeyKindInvalid
   314  	}
   315  	return p.get(key, khash)
   316  }
   317  
   318  func (b *Bitpage) makeFilePath(ft FileType, pn PageNum, fn FileNum) string {
   319  	return makeFilepath(b.dirname, ft, pn, fn)
   320  }
   321  
   322  func (b *Bitpage) NewIter(pn PageNum, o *iterOptions) *PageIterator {
   323  	p := b.GetPage(pn)
   324  	if p == nil {
   325  		return nil
   326  	}
   327  
   328  	return p.newIter(o)
   329  }
   330  
   331  func (b *Bitpage) GetPageWriter(pn PageNum, sentinel []byte) *PageWriter {
   332  	pageWriter, ok := b.pageWriters.Load(pn)
   333  	if ok {
   334  		return pageWriter.(*PageWriter)
   335  	}
   336  
   337  	p := b.GetPage(pn)
   338  	if p == nil {
   339  		return nil
   340  	}
   341  
   342  	writer := &PageWriter{
   343  		p:        p,
   344  		Sentinel: utils.CloneBytes(sentinel),
   345  	}
   346  	b.pageWriters.Store(pn, writer)
   347  
   348  	return writer
   349  }
   350  
   351  func (b *Bitpage) Close() (err error) {
   352  	b.pages.Range(func(pn, p interface{}) bool {
   353  		err = p.(*page).close(false)
   354  		return true
   355  	})
   356  
   357  	if b.meta != nil {
   358  		if err = b.meta.close(); err != nil {
   359  			b.opts.Logger.Errorf("bitpage close meta fail dir:%s err:%s", b.dirname, err.Error())
   360  		}
   361  	}
   362  
   363  	if b.cache != nil {
   364  		b.cache.Close()
   365  	}
   366  
   367  	return nil
   368  }
   369  
   370  func (b *Bitpage) GetNeedFlushPageNums(isForce bool) []PageNum {
   371  	var pns []PageNum
   372  	b.pages.Range(func(pn, p interface{}) bool {
   373  		if pg, ok := p.(*page); ok {
   374  			if pg.maybeScheduleFlush(b.opts.BitpageFlushSize, isForce) {
   375  				pns = append(pns, pn.(PageNum))
   376  			}
   377  		}
   378  		return true
   379  	})
   380  	return pns
   381  }
   382  
   383  func (b *Bitpage) GetPageCount() int {
   384  	count := 0
   385  	b.pages.Range(func(pn, p interface{}) bool {
   386  		count++
   387  		return true
   388  	})
   389  	return count
   390  }
   391  
   392  func (b *Bitpage) PageFlush(pn PageNum, sentinel []byte, logTag string) error {
   393  	p := b.GetPage(pn)
   394  	if p == nil {
   395  		return ErrPageNotFound
   396  	}
   397  
   398  	defer p.setFlushState(pageFlushStateNone)
   399  
   400  	if !p.canFlush() {
   401  		return ErrPageFlushState
   402  	}
   403  
   404  	if b.PageSplitted(pn) {
   405  		return ErrPageSplitted
   406  	}
   407  
   408  	return p.flush(sentinel, logTag)
   409  }
   410  
   411  func (b *Bitpage) ManualPageFlush(pn PageNum) error {
   412  	p := b.GetPage(pn)
   413  	if p == nil {
   414  		return ErrPageNotFound
   415  	}
   416  
   417  	p.setFlushState(pageFlushStateSendTask)
   418  	return b.PageFlush(pn, nil, "")
   419  }
   420  
   421  func (b *Bitpage) PageSplitStart(pn PageNum, log string) (sps []*SplitPageInfo, err error) {
   422  	p := b.GetPage(pn)
   423  	if p == nil {
   424  		err = ErrPageNotFound
   425  		return
   426  	}
   427  
   428  	if b.meta.getSplitState(pn) >= pageSplitStateStart {
   429  		err = ErrPageSplitted
   430  		return
   431  	}
   432  	b.meta.setSplitState(pn, pageSplitStateStart)
   433  
   434  	var pages [consts.BitpageSplitNum]*page
   435  	var pns [consts.BitpageSplitNum]uint32
   436  	splitNum := consts.BitpageSplitNum
   437  	for i := 0; i < splitNum; i++ {
   438  		pages[i], err = b.newPageInternal()
   439  		if err != nil {
   440  			return
   441  		}
   442  
   443  		pns[i] = uint32(pages[i].pn)
   444  	}
   445  
   446  	logTag := fmt.Sprintf("%s split %s to %v", log, p.pn, pns)
   447  	if err = p.split(logTag, pages[:]); err != nil {
   448  		return
   449  	}
   450  
   451  	for i := 0; i < splitNum; i++ {
   452  		if pages[i] != nil {
   453  			sps = append(sps, &SplitPageInfo{
   454  				Pn:       pages[i].pn,
   455  				Sentinel: pages[i].maxKey,
   456  			})
   457  		}
   458  	}
   459  
   460  	return
   461  }
   462  
   463  func (b *Bitpage) PageSplitEnd(pn PageNum, sps []*SplitPageInfo, retErr error) {
   464  	if retErr == nil {
   465  		for i := range sps {
   466  			b.meta.setNextArrayTableFileNum(sps[i].Pn)
   467  		}
   468  		b.markFreePage(pn)
   469  	} else {
   470  		if retErr == ErrPageSplitted || retErr == ErrPageNotFound {
   471  			return
   472  		}
   473  
   474  		b.setPageNoneSplit(pn)
   475  		for i := range sps {
   476  			if err := b.FreePage(sps[i].Pn, false); err != nil {
   477  				b.opts.Logger.Errorf("PageSplitEnd FreePage fail index:%d pn:%s err:%s", b.index, sps[i].Pn, err)
   478  			}
   479  		}
   480  	}
   481  }
   482  
   483  func (b *Bitpage) ResetStats() {
   484  	b.stats.Reset()
   485  }
   486  
   487  func (b *Bitpage) Stats() *Stats {
   488  	b.stats.Size = utils.GetDirSize(b.dirname)
   489  
   490  	return b.stats
   491  }
   492  
   493  func (b *Bitpage) StatsToString() string {
   494  	return b.stats.String()
   495  }
   496  
   497  func (b *Bitpage) deleteBithashKey(value []byte) {
   498  	if len(value) == 0 {
   499  		return
   500  	}
   501  
   502  	dv := base.DecodeInternalValue(value)
   503  	if dv.Kind() == base.InternalKeyKindSetBithash && base.CheckValueValidByKeySetBithash(dv.UserValue) {
   504  		fn := binary.LittleEndian.Uint32(dv.UserValue)
   505  		if err := b.opts.BithashDeleteCB(fn); err != nil {
   506  			b.opts.Logger.Errorf("delete bithash key fail err:%v", err)
   507  		}
   508  	}
   509  }
   510  
   511  func (b *Bitpage) getStArenaBuf(sz int) []byte {
   512  	alloc := utils.CalcBitsSize(sz)
   513  
   514  	if b.stArena == nil {
   515  		b.stArena = arena.NewArena()
   516  		b.stArenaBuf = arena.MakeSlice[byte](b.stArena, alloc, alloc)
   517  	} else if cap(b.stArenaBuf) < sz {
   518  		b.stArena.Free()
   519  		b.stArena = arena.NewArena()
   520  		b.stArenaBuf = arena.MakeSlice[byte](b.stArena, alloc, alloc)
   521  	}
   522  
   523  	return b.stArenaBuf
   524  }
   525  
   526  func (b *Bitpage) freeStArenaBuf() {
   527  	if b.stArena != nil {
   528  		b.stArena.Free()
   529  		b.stArena = nil
   530  		b.stArenaBuf = nil
   531  	}
   532  }