/**
 * Copyright (c) 2018-present, heineiuo.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ import { FileMetaData } from "./VersionFormat" ; import Version from "./Version" ; import VersionEdit from "./VersionEdit" ; import { Options } from "./Options" ; import Slice from "./Slice" ; import SSTableBuilder from "./SSTableBuilder" ; import { Config , InternalKey , SequenceNumber } from "./Format" ; import { FileHandle } from "./Env" ; export default class Compaction { static targetFileSize ( options ) { return options . maxFileSize ; } static maxGrandParentOverlapBytes ( options ) { return 10 * Compaction . targetFileSize ( options ) ; } static totalFileSize ( files ) { let sum = 0 ; for ( const file of files ) { sum += file . fileSize ; } return sum ; } static maxFileSizeForLevel ( options , level ) { return Compaction . targetFileSize ( options ) ; } constructor ( options , level ) { this . level = level ; this . grandparentIndex = 0 ; this . overlappedBytes = 0 ; this . seenKey = false ; this . inputs = [ [ ] , [ ] ] ; this . _maxOutputFilesize = Compaction . maxFileSizeForLevel ( options , level ) ; this . levelPtrs = Array . from ( { length : Config . kNumLevels } , ( ) => 0 ) ; this . edit = new VersionEdit ( ) ; } public level : number ; public inputVersion ! : Version ; public grandparents ! : FileMetaData [ ] ; public edit : VersionEdit ; public inputs : [ FileMetaData [ ] , FileMetaData [ ] ] ; private grandparentIndex : number ; private seenKey : boolean ; private overlappedBytes : number ; private _maxOutputFilesize : number ; private levelPtrs : number [ ] ; get maxOutputFilesize ( ) : number { return this . _maxOutputFilesize ; } public numInputFiles ( which ) { return this . inputs [ which ] . length ; } public isTrivialMove ( ) { const versionSet = this . inputVersion . versionSet ; return ( this . numInputFiles ( 0 ) === 1 && this . numInputFiles ( 1 ) === 0 && Compaction . totalFileSize ( this . grandparents ) <= Compaction . maxGrandParentOverlapBytes ( versionSet . _options ) ) ; } public isBaseLevelForKey ( userKey ) { const userComparator = this . inputVersion . versionSet . internalKeyComparator . userComparator ; for ( let level = this . level + 2 ; level < Config . kNumLevels ; level ++ ) { const files = this . inputVersion . files [ level ] ; while ( this . levelPtrs [ level ] < files . length ) { const f = files [ this . levelPtrs [ level ] ] ; if ( userComparator . compare ( userKey , f . largest . userKey ) <= 0 ) { if ( userComparator . compare ( userKey , f . smallest . userKey ) >= 0 ) { return false ; } break ; } this . levelPtrs [ level ] ++ ; } } return true ; } public releaseInputs ( ) { if ( ! ! this . inputVersion ) { this . inputVersion . unref ( ) ; delete this . inputVersion ; } } /**
     * Returns true if we should stop building the current output
     * before processing "internalKey".
     */ public shouldStopBefore ( internalKey ) { const versionSet = this . inputVersion . versionSet ; const icmp = versionSet . internalKeyComparator ; while ( this . grandparentIndex < this . grandparents . length && icmp . compare ( internalKey , this . grandparents [ this . grandparentIndex ] . largest ) > 0 ) { if ( this . seenKey ) { this . overlappedBytes += this . grandparents [ this . grandparentIndex ] . fileSize ; } this . grandparentIndex ++ ; } this . seenKey = true ; if ( this . overlappedBytes > Compaction . maxGrandParentOverlapBytes ( versionSet . _options ) ) { this . overlappedBytes = 0 ; return true ; } else { return false ; } } public addInputDeletions ( edit ) { for ( let which = 0 ; which < 2 ; which ++ ) { for ( let i = 0 ; i < this . inputs [ which ] . length ; i ++ ) { edit . deleteFile ( this . level + which , this . inputs [ which ] [ i ] . number ) ; } } } } export class CompactionStats { times : number ; bytesRead : number ; bytesWritten : number ; constructor ( ) { this . times = 0 ; this . bytesRead = 0 ; this . bytesWritten = 0 ; } add ( c ) { this . times += c . times ; this . bytesRead += c . bytesRead ; this . bytesWritten += c . bytesWritten ; } } export interface CompactionStateOutput { number : number ; fileSize : number ; smallest : InternalKey ; largest : InternalKey ; } export class CompactionState { public outputs : CompactionStateOutput [ ] = [ ] ; public smallestSnapshot : SequenceNumber ; public compaction : Compaction ; public outfile ! : FileHandle ; public builder ! : SSTableBuilder ; public totalBytes : number ; constructor ( c ) { this . compaction = c ; this . smallestSnapshot = 0n ; this . totalBytes = 0 ; } public currentOutput ( ) { return this . outputs [ this . outputs . length - 1 ] ; } }