github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bitable.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  	"io"
    19  	"time"
    20  
    21  	"github.com/zuoyebang/bitalosdb/bitable"
    22  	"github.com/zuoyebang/bitalosdb/bitpage"
    23  	"github.com/zuoyebang/bitalosdb/internal/base"
    24  	"github.com/zuoyebang/bitalosdb/internal/consts"
    25  	"github.com/zuoyebang/bitalosdb/internal/options"
    26  	"github.com/zuoyebang/bitalosdb/internal/utils"
    27  )
    28  
    29  func (t *Bitree) newBitableIter(o *options.IterOptions) *bitable.BitableIterator {
    30  	if t.btable == nil {
    31  		return nil
    32  	}
    33  
    34  	return t.btable.NewIter(o)
    35  }
    36  
    37  func (t *Bitree) bitableExist(key []byte) bool {
    38  	_, closer, err := t.bitableGet(key)
    39  	if closer != nil {
    40  		closer.Close()
    41  	}
    42  
    43  	return err != base.ErrNotFound
    44  }
    45  
    46  func (t *Bitree) bitableGet(key []byte) ([]byte, io.Closer, error) {
    47  	if t.btable == nil || !t.opts.IsFlushedBitableCB() {
    48  		return nil, nil, base.ErrNotFound
    49  	}
    50  
    51  	return t.btable.Get(key)
    52  }
    53  
    54  func (t *Bitree) bitableDelete(key []byte) error {
    55  	if t.btable == nil || !t.opts.IsFlushedBitableCB() {
    56  		return nil
    57  	}
    58  
    59  	val, closer, err := t.btable.Get(key)
    60  	if closer != nil {
    61  		_ = closer.Close()
    62  	}
    63  	if err == base.ErrNotFound {
    64  		return nil
    65  	}
    66  
    67  	t.DeleteBithashKey(val)
    68  
    69  	return t.btable.Delete(key)
    70  }
    71  
    72  func (t *Bitree) ManualCompact() error {
    73  	if t.btable == nil {
    74  		return nil
    75  	}
    76  
    77  	err := t.btable.Compact(nil, []byte{0xff, 0xff}, false)
    78  	return err
    79  }
    80  
    81  func (t *Bitree) CompactBitreeToBitable() (pn bitpage.PageNum) {
    82  	if t.btable == nil {
    83  		return
    84  	}
    85  
    86  	t.dbState.WaitBitowerHighPriority(t.index)
    87  	t.dbState.LockBitowerWrite(t.index)
    88  	defer t.dbState.UnlockBitowerWrite(t.index)
    89  
    90  	start := time.Now()
    91  
    92  	deleteBitable := func(batch *bitable.BitableBatch, key []byte) {
    93  		btVal, closer, btErr := t.bitableGet(key)
    94  		defer func() {
    95  			if closer != nil {
    96  				closer.Close()
    97  			}
    98  		}()
    99  		if btErr != base.ErrNotFound {
   100  			t.DeleteBithashKey(btVal)
   101  			_ = batch.Delete(key)
   102  		}
   103  	}
   104  
   105  	flushToBitable := func(ciMaxSize int) error {
   106  		t.btable.CloseAutomaticCompactions()
   107  		defer t.btable.OpenAutomaticCompactions()
   108  
   109  		iter := t.newBitreeIter(nil)
   110  		defer iter.Close()
   111  
   112  		iter.SetCompact()
   113  		ciFlushSize := ciMaxSize - 6<<20
   114  		var batch *bitable.BitableBatch
   115  		var err error
   116  
   117  		for k, v := iter.First(); k != nil; k, v = iter.Next() {
   118  			if batch == nil {
   119  				batch = t.btable.NewFlushBatch(ciMaxSize)
   120  			}
   121  
   122  			switch k.Kind() {
   123  			case base.InternalKeyKindSet:
   124  				if t.opts.BitpageOpts.CheckExpireCB(k.UserKey, v) {
   125  					deleteBitable(batch, k.UserKey)
   126  				} else {
   127  					_ = batch.Set(k.UserKey, v)
   128  				}
   129  			case base.InternalKeyKindDelete:
   130  				deleteBitable(batch, k.UserKey)
   131  			}
   132  
   133  			if batch.Size() > ciFlushSize {
   134  				if err = batch.Commit(); err != nil {
   135  					return err
   136  				}
   137  				_ = batch.Close()
   138  				batch = nil
   139  			}
   140  
   141  			if err != nil {
   142  				t.opts.Logger.Errorf("[COMPACTBITABLE %d] flushToBitable write fail err:%s", t.index, err)
   143  				err = nil
   144  			}
   145  		}
   146  
   147  		if batch == nil {
   148  			return nil
   149  		}
   150  
   151  		err = batch.Commit()
   152  		_ = batch.Close()
   153  		batch = nil
   154  		return err
   155  	}
   156  
   157  	if err := flushToBitable(consts.CompactToBitableCiMaxSize); err != nil {
   158  		t.opts.Logger.Errorf("[COMPACTBITABLE %d] flushToBitable fail err:%s", t.index, err)
   159  		return
   160  	}
   161  
   162  	resetBitree := func() error {
   163  		tx, err := t.bdb.Begin(true)
   164  		if err != nil {
   165  			return err
   166  		}
   167  		defer func() {
   168  			if err != nil {
   169  				_ = tx.Rollback()
   170  			}
   171  		}()
   172  
   173  		bkt := tx.Bucket(consts.BdbBucketName)
   174  		if bkt == nil {
   175  			err = ErrBucketNotExist
   176  			return err
   177  		}
   178  
   179  		it := t.NewBdbIter()
   180  		defer it.Close()
   181  
   182  		var pns []bitpage.PageNum
   183  		for k, v := it.First(); k != nil; k, v = it.Next() {
   184  			if err = bkt.Delete(k.UserKey); err != nil {
   185  				return err
   186  			}
   187  			pns = append(pns, bitpage.PageNum(utils.BytesToUint32(v)))
   188  		}
   189  
   190  		pn, err = t.bpage.NewPage()
   191  		if err != nil {
   192  			return err
   193  		}
   194  		defer func() {
   195  			if err != nil {
   196  				_ = t.bpage.FreePage(pn, false)
   197  			}
   198  		}()
   199  
   200  		if err = bkt.Put(consts.BdbMaxKey, pn.ToByte()); err != nil {
   201  			return err
   202  		}
   203  
   204  		if err = tx.Commit(); err != nil {
   205  			return err
   206  		}
   207  
   208  		t.bpage.MarkFreePages(pns)
   209  		return nil
   210  	}
   211  
   212  	if err := resetBitree(); err != nil {
   213  		pn = nilPageNum
   214  		t.opts.Logger.Errorf("[COMPACTBITABLE %d] bdbReset fail err:%s", t.index, err)
   215  	}
   216  
   217  	if !t.BdbUpdate() {
   218  		t.opts.Logger.Errorf("[COMPACTBITABLE %d] bdb txPool swaptx fail", t.index)
   219  	}
   220  
   221  	t.bpage.ResetStats()
   222  	t.opts.Logger.Infof("[COMPACTBITABLE %d] compact finish cost:%.3fs", t.index, time.Since(start).Seconds())
   223  
   224  	return
   225  }
   226  
   227  func (t *Bitree) BitableDebugInfo(dataType string) string {
   228  	if t.btable == nil || !t.opts.IsFlushedBitableCB() {
   229  		return ""
   230  	}
   231  	return t.btable.DebugInfo(dataType)
   232  }