github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/flush_external.go (about) 1 // Copyright 2020 The LevelDB-Go and Pebble and Bitalostored Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package bitalostable 6 7 import ( 8 "time" 9 10 "github.com/zuoyebang/bitalostable/internal/private" 11 ) 12 13 // flushExternalTable is installed as the private.FlushExternalTable hook. 14 // It's used by the internal/replay package to flush external tables into L0 15 // for supporting the bitalostable bench compact commands. Clients should use the 16 // replay package rather than calling this private hook directly. 17 func flushExternalTable(untypedDB interface{}, path string, originalMeta *fileMetadata) error { 18 d := untypedDB.(*DB) 19 if err := d.closed.Load(); err != nil { 20 panic(err) 21 } 22 if d.opts.ReadOnly { 23 return ErrReadOnly 24 } 25 26 d.mu.Lock() 27 fileNum := d.mu.versions.getNextFileNum() 28 jobID := d.mu.nextJobID 29 d.mu.nextJobID++ 30 d.mu.Unlock() 31 32 m := &fileMetadata{ 33 FileNum: fileNum, 34 Size: originalMeta.Size, 35 CreationTime: time.Now().Unix(), 36 SmallestSeqNum: originalMeta.SmallestSeqNum, 37 LargestSeqNum: originalMeta.LargestSeqNum, 38 } 39 if originalMeta.HasPointKeys { 40 m.ExtendPointKeyBounds(d.cmp, originalMeta.SmallestPointKey, originalMeta.LargestPointKey) 41 } 42 if originalMeta.HasRangeKeys { 43 m.ExtendRangeKeyBounds(d.cmp, originalMeta.SmallestRangeKey, originalMeta.LargestRangeKey) 44 } 45 46 // Hard link the sstable into the DB directory. 47 if err := ingestLink(jobID, d.opts, d.dirname, []string{path}, []*fileMetadata{m}); err != nil { 48 return err 49 } 50 if err := d.dataDir.Sync(); err != nil { 51 return err 52 } 53 54 // Assign sequence numbers from its current value through to the 55 // external file's largest sequence number. It's possible that the current 56 // sequence number has already exceeded m.LargestSeqNum if there were many 57 // nonoverlapping ingestions, so skip if this doesn't bump the sequence 58 // number. 59 d.commit.ratchetSeqNum(m.LargestSeqNum + 1) 60 d.commit.mu.Lock() 61 defer d.commit.mu.Unlock() 62 63 // Apply the version edit. 64 d.mu.Lock() 65 d.mu.versions.logLock() 66 ve := &versionEdit{ 67 NewFiles: []newFileEntry{{Level: 0, Meta: m}}, 68 } 69 metrics := map[int]*LevelMetrics{ 70 0: { 71 NumFiles: 1, 72 Size: int64(m.Size), 73 BytesIngested: m.Size, 74 TablesIngested: 1, 75 }, 76 } 77 err := d.mu.versions.logAndApply(jobID, ve, metrics, false /* forceRotation */, func() []compactionInfo { 78 return d.getInProgressCompactionInfoLocked(nil) 79 }) 80 if err != nil { 81 // NB: logAndApply will release d.mu.versions.logLock unconditionally. 82 d.mu.Unlock() 83 if err2 := ingestCleanup(d.opts.FS, d.dirname, []*fileMetadata{m}); err2 != nil { 84 d.opts.Logger.Infof("flush external cleanup failed: %v", err2) 85 } 86 return err 87 } 88 d.updateReadStateLocked(d.opts.DebugCheck) 89 d.updateTableStatsLocked(ve.NewFiles) 90 d.deleteObsoleteFiles(jobID, true /* waitForOngoing */) 91 d.maybeScheduleCompaction() 92 d.mu.Unlock() 93 return nil 94 } 95 96 // ratchetSeqNum is a hook for allocating and publishing sequence numbers up 97 // to a specific absolute value. Its first parameter is a *bitalostable.DB and its 98 // second is the new next sequence number. RatchetSeqNum does nothing if the 99 // next sequence is already greater than or equal to nextSeqNum. 100 // 101 // This function is used by the internal/replay package to ensure replayed 102 // operations receive the same absolute sequence number. 103 func ratchetSeqNum(untypedDB interface{}, nextSeqNum uint64) { 104 d := untypedDB.(*DB) 105 d.commit.ratchetSeqNum(nextSeqNum) 106 } 107 108 func init() { 109 private.FlushExternalTable = flushExternalTable 110 private.RatchetSeqNum = ratchetSeqNum 111 }