/**
 * 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 { assert , varint } from "./DBHelper" ; import { Buffer } from "./Buffer" ; import Slice from "./Slice" ; import { Comparator } from "./Comparator" ; import { decodeFixed64 , encodeFixed64 , decodeFixed32 } from "./Coding" ; import BloomFilter from "./BloomFilter" ; export enum FileType { kLogFile , kDBLockFile , kTableFile , kDescriptorFile , kCurrentFile , kTempFile , kInfoLogFile } export enum ValueType { kTypeDeletion = 0x00 , kTypeValue = 0x01 } export const kValueTypeForSeek = ValueType . kTypeValue ; export type SequenceNumber = bigint ; export const kMaxSequenceNumber = ( 1n << 56n ) - 1n ; export class ParsedInternalKey { constructor ( userKey ? , sn ? , valueType ? ) { if ( typeof userKey !== "undefined" && typeof sn !== "undefined" && typeof valueType !== "undefined" ) { this . userKey = userKey ; this . sn = sn ; this . valueType = valueType ; } } userKey ! : Slice ; sn ! : SequenceNumber ; valueType ! : ValueType ; } function packSequenceAndType ( seq , t ) { const bSeq = BigInt ( seq ) ; assert ( bSeq <= kMaxSequenceNumber ) ; assert ( t <= kValueTypeForSeek ) ; return ( bSeq << 8n ) | BigInt ( t ) ; } function appendInternalKey ( buf , key ) { const sequenceBuf = encodeFixed64 ( key . sn ) ; sequenceBuf . fillInt ( key . valueType , 7 , 8 ) ; return Buffer . concat ( [ buf , key . userKey . buffer , sequenceBuf ] ) ; } export enum VersionEditTag { kComparator = 1 , kLogNumber = 2 , kNextFileNumber = 3 , kLastSequence = 4 , kCompactPointer = 5 , kDeletedFile = 6 , kNewFile = 7 , kPrevLogNumber = 9 } export enum CompressionTypes { none = 0x00 } export function extractUserKey ( ikey ) { assert ( ikey . size >= 8 ) ; return new Slice ( ikey . buffer . slice ( 0 , ikey . size - 8 ) ) ; } export class InternalKey extends Slice { static kMaxSequenceNumber : SequenceNumber = 72057594037927935n ; static from ( slice ) { const internalKey = new InternalKey ( ) ; assert ( internalKey . decodeFrom ( slice ) ) ; return internalKey ; } constructor ( userKey ? , sn ? , valueType ? ) { super ( ) ; if ( typeof userKey !== "undefined" && typeof sn !== "undefined" && typeof valueType !== "undefined" ) { this . buffer = appendInternalKey ( this . buffer , new ParsedInternalKey ( userKey , sn , valueType ) ) ; } } get userKey ( ) : Slice { return extractUserKey ( this ) ; } get type ( ) : ValueType { return this . buffer [ this . buffer . length - 1 ] ; } get sequence ( ) : number { const sequenceBuf = Buffer . alloc ( 8 ) ; sequenceBuf . fillBuffer ( this . buffer . slice ( this . buffer . length - 8 ) , 0 , 7 ) ; return decodeFixed32 ( sequenceBuf ) ; } public decodeFrom ( slice ) { this . buffer = slice . buffer ; return this . buffer . length > 0 ; } } export class InternalKeyBuilder { build ( sequence , valueType , key ) { /**
         * encoded(internal_key_size) | key | sequence(7Bytes) | type (1Byte) | encoded(value_size) | value
         * 1. Lookup key/ Memtable Key: encoded(internal_key_size) --- type(1Byte)
         * 2. Internal key: key --- type(1Byte)
         * 3. User key: key
         */ const sequenceBuf = encodeFixed64 ( sequence ) ; sequenceBuf . fillInt ( valueType , 7 , 8 ) ; const slice = new Slice ( Buffer . concat ( [ key . buffer , sequenceBuf ] ) ) ; return new InternalKey ( slice ) ; } } export const kBlockTrailerSize = 5 ; export class Config { static kNumLevels = 7 ; static kL0CompactionTrigger = 4 ; static kL0SlowdownWritesTrigger = 8 ; static kL0StopWritesTrigger = 12 ; static kMaxMemCompactLevel = 2 ; static kReadBytesPeriod = 1048576 ; } export const kSizeOfUInt32 = 4 ; export class InternalKeyComparator implements Comparator { constructor ( userComparator ) { this . _userComparator = userComparator ; } private _userComparator : Comparator ; private oneByte = Buffer . alloc ( 1 ) ; get userComparator ( ) : Comparator { return this . _userComparator ; } getName ( ) { return "leveldb.InternalKeyComparator" ; } findShortestSeparator ( start , limit ) { const userStart = extractUserKey ( start ) ; const userLimit = extractUserKey ( limit ) ; const tmp = new Slice ( Buffer . fromUnknown ( userStart . buffer ) ) ; this . userComparator . findShortestSeparator ( tmp , userLimit ) ; if ( tmp . size < userStart . size && this . userComparator . compare ( userStart , tmp ) < 0 ) { tmp . buffer = Buffer . concat ( [ tmp . buffer , encodeFixed64 ( packSequenceAndType ( kMaxSequenceNumber , kValueTypeForSeek ) ) , ] ) ; assert ( this . compare ( start , tmp ) < 0 ) ; assert ( this . compare ( tmp , limit ) < 0 ) ; start . buffer = tmp . buffer ; } } findShortSuccessor ( key ) { const userKey = extractUserKey ( key ) ; const tmp = new Slice ( Buffer . fromUnknown ( userKey . buffer ) ) ; this . _userComparator . findShortSuccessor ( tmp ) ; if ( tmp . size < userKey . size && this . _userComparator . compare ( userKey , tmp ) < 0 ) { tmp . buffer = Buffer . concat ( [ tmp . buffer , encodeFixed64 ( packSequenceAndType ( kMaxSequenceNumber , kValueTypeForSeek ) ) , ] ) ; assert ( this . compare ( key , tmp ) < 0 ) ; key . buffer = tmp . buffer ; } } compare ( key1 , key2 ) { const userKey1 = extractUserKey ( key1 ) ; const userKey2 = extractUserKey ( key2 ) ; const r = this . userComparator . compare ( userKey1 , userKey2 ) ; if ( r !== 0 ) return r ; const sn1 = decodeFixed64 ( Buffer . concat ( [ key1 . buffer . slice ( key1 . size - 8 , key1 . size - 1 ) , this . oneByte , ] ) ) ; const sn2 = decodeFixed64 ( Buffer . concat ( [ key2 . buffer . slice ( key2 . size - 8 , key2 . size - 1 ) , this . oneByte , ] ) ) ; if ( sn1 === sn2 ) return 0 ; return sn1 > sn2 ? - 1 : 1 ; } } export function parseInternalKey ( internalKey , ikey ) { try { ikey . userKey = extractUserKey ( internalKey ) ; const snBuf = Buffer . alloc ( 8 ) ; snBuf . fillBuffer ( internalKey . buffer . slice ( internalKey . length - 8 ) , 0 , 7 ) ; ikey . sn = decodeFixed64 ( snBuf ) ; ikey . valueType = internalKey . buffer [ internalKey . length - 1 ] ; return true ; } catch ( e ) { return false ; } } export class LookupKey { constructor ( userKey , sequence ) { this . _userKeyBuf = userKey . buffer ; this . _internalKeySizeBuf = Buffer . fromUnknown ( varint . encode ( userKey . size + 8 ) ) ; this . _sequenceBuf = encodeFixed64 ( sequence ) ; this . _sequenceBuf . fillBuffer ( Buffer . fromUnknown ( varint . encode ( kValueTypeForSeek ) ) , 7 ) ; } private _internalKeySizeBuf : Buffer ; private _userKeyBuf : Buffer ; private _sequenceBuf : Buffer ; get buffer ( ) : Buffer { return Buffer . concat ( [ this . _internalKeySizeBuf , this . _userKeyBuf , this . _sequenceBuf , ] ) ; } get internalKey ( ) : Slice { return new Slice ( Buffer . concat ( [ this . _userKeyBuf , this . _sequenceBuf ] ) ) ; } get memKey ( ) : Slice { return new Slice ( this . buffer ) ; } get userKey ( ) : Slice { return new Slice ( this . _userKeyBuf ) ; } set userKey ( userKey ) { this . _userKeyBuf = userKey . buffer ; this . _internalKeySizeBuf = Buffer . fromUnknown ( varint . encode ( userKey . size + 8 ) ) ; } } export interface Entry { sequence ? : SequenceNumber ; type ? : ValueType ; key : Slice ; value : Slice ; } export interface EntryRequireType extends Entry { type : ValueType ; } export interface Filter extends BloomFilter { } export class BlockHandle { static from ( buf ) { const handle = new BlockHandle ( ) ; handle . offset = varint . decode ( buf ) ; handle . size = varint . decode ( buf , varint . decode . bytes ) ; return handle ; } offset ! : number ; size ! : number ; get buffer ( ) : Buffer { assert ( typeof this . offset === "number" ) ; assert ( typeof this . size === "number" ) ; return Buffer . concat ( [ Buffer . fromUnknown ( varint . encode ( this . offset ) ) , Buffer . fromUnknown ( varint . encode ( this . size ) ) , ] ) ; } } export interface MetaBlockEntry { name : string ; handle : BlockHandle ; } export interface DataBlockEntry { largest : Slice ; handle : BlockHandle ; } export interface BlockContents { data : Slice ; cachable : boolean ; heapAllocated : boolean ; }