/**
 * 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 { Buffer } from "./Buffer" ; import { assert , varint } from "./DBHelper" ; import Slice from "./Slice" ; import MemTable from "./MemTable" ; import LogRecord from "./LogRecord" ; import { SequenceNumber , EntryRequireType , ValueType } from "./Format" ; import { decodeFixed64 , encodeFixed32 , decodeFixed32 , encodeFixed64 , } from "./Coding" ; export class WriteBatchInternal { static kHeader = 12 ; static byteSize ( batch ) { return batch . buffers . reduce ( ( size , buf ) => size + buf . length , 0 ) ; } static insert ( batch , mem ) { let nextSequence = WriteBatchInternal . getSequence ( batch ) ; for ( const update of batch . iterator ( ) ) { const { type , key , value } = update ; mem . add ( nextSequence , type , key , value ) ; nextSequence += 1n ; } } static getContents ( batch ) { return Buffer . concat ( [ batch . head , ... batch . buffers ] ) ; } static setContents ( batch , contents ) { assert ( contents . length >= WriteBatchInternal . kHeader ) ; batch . head = contents . slice ( 0 , this . kHeader ) ; batch . buffers = [ contents . slice ( this . kHeader ) ] ; } static setSequence ( batch , sequence ) { batch . head . fillBuffer ( encodeFixed64 ( sequence ) , 0 , 7 ) ; } static getSequence ( batch ) { return decodeFixed64 ( batch . head . slice ( 0 , 8 ) ) ; } static setCount ( batch , count ) { batch . head . fillBuffer ( encodeFixed32 ( count ) , 8 , 11 ) ; } static getCount ( batch ) { return decodeFixed32 ( batch . head . slice ( 8 , 12 ) ) ; } static append ( dst , src ) { WriteBatchInternal . setCount ( dst , WriteBatchInternal . getCount ( src ) + WriteBatchInternal . getCount ( dst ) ) ; dst . buffers = dst . buffers . concat ( src . buffers ) ; } } export class WriteBatch { buffers : Buffer [ ] = [ ] ; head : Buffer = Buffer . alloc ( WriteBatchInternal . kHeader ) ; put ( key , value ) { const record = LogRecord . add ( new Slice ( key ) , new Slice ( value ) ) ; this . buffers . push ( record . buffer ) ; WriteBatchInternal . setCount ( this , WriteBatchInternal . getCount ( this ) + 1 ) ; } del ( key ) { const record = LogRecord . del ( new Slice ( key ) ) ; this . buffers . push ( record . buffer ) ; WriteBatchInternal . setCount ( this , WriteBatchInternal . getCount ( this ) + 1 ) ; } clear ( ) { this . buffers = [ ] ; this . head = Buffer . alloc ( WriteBatchInternal . kHeader ) ; } * iterator ( ) { let buffersIndex = 0 ; const buffersCount = this . buffers . length ; while ( buffersIndex < buffersCount ) { const buffer = this . buffers [ buffersIndex ] ; const bufferLength = buffer . length ; let index = 0 ; while ( index < bufferLength ) { const valueType = buffer . readUInt8 ( index ) ; index ++ ; const keyLength = varint . decode ( buffer , index ) ; index += varint . decode . bytes ; const keyBuffer = buffer . slice ( index , index + keyLength ) ; index += keyLength ; if ( valueType === ValueType . kTypeDeletion ) { yield { type : valueType , key : new Slice ( keyBuffer ) , value : new Slice ( ) , } ; continue ; } const valueLength = varint . decode ( buffer , index ) ; index += varint . decode . bytes ; const valueBuffer = buffer . slice ( index , index + valueLength ) ; index += valueLength ; yield { type : valueType , key : new Slice ( keyBuffer ) , value : new Slice ( valueBuffer ) , } ; } buffersIndex ++ ; } } }