一個(gè)巧妙的迭代器

import (
    "encoding/binary"
)

const batchHeaderLen = 12

const invalidBatchCount = 1<<32 - 1

// Batch is a sequence of Sets and/or Deletes that are applied atomically.
type Batch struct {
    // Data is the wire format of a batch's log entry:
    //   - 8 bytes for a sequence number of the first batch element,
    //     or zeroes if the batch has not yet been applied,
    //   - 4 bytes for the count: the number of elements in the batch,
    //     or "\xff\xff\xff\xff" if the batch is invalid,
    //   - count elements, being:
    //     - one byte for the kind: delete (0) or set (1),
    //     - the varint-string user key,
    //     - the varint-string value (if kind == set).
    // The sequence number and count are stored in little-endian order.
    data []byte
}

// Set adds an action to the batch that sets the key to map to the value.
func (b *Batch) Set(key, value []byte) {
    if len(b.data) == 0 {
        b.init(len(key) + len(value) + 2*binary.MaxVarintLen64 + batchHeaderLen)
    }
    if b.increment() {
        b.data = append(b.data, byte(internalKeyKindSet))
        b.appendStr(key)
        b.appendStr(value)
    }
}

// Delete adds an action to the batch that deletes the entry for key.
func (b *Batch) Delete(key []byte) {
    if len(b.data) == 0 {
        b.init(len(key) + binary.MaxVarintLen64 + batchHeaderLen)
    }
    if b.increment() {
        b.data = append(b.data, byte(internalKeyKindDelete))
        b.appendStr(key)
    }
}

func (b *Batch) init(cap int) {
    n := 256
    for n < cap {
        n *= 2
    }
    b.data = make([]byte, batchHeaderLen, n)
}

// seqNumData returns the 8 byte little-endian sequence number. Zero means that
// the batch has not yet been applied.
func (b *Batch) seqNumData() []byte {
    return b.data[:8]
}

// countData returns the 4 byte little-endian count data. "\xff\xff\xff\xff"
// means that the batch is invalid.
func (b *Batch) countData() []byte {
    return b.data[8:12]
}

func (b *Batch) increment() (ok bool) {
    p := b.countData() // [8:12]
    for i := range p {
        p[i]++
        if p[i] != 0x00 {
            return true
        } //
    }
    // The countData was "\xff\xff\xff\xff". Leave it as it was.
    p[0] = 0xff
    p[1] = 0xff
    p[2] = 0xff
    p[3] = 0xff
    return false
}

func (b *Batch) appendStr(s []byte) {
    var buf [binary.MaxVarintLen64]byte
    n := binary.PutUvarint(buf[:], uint64(len(s)))
    b.data = append(b.data, buf[:n]...)
    b.data = append(b.data, s...)
}

func (b *Batch) setSeqNum(seqNum uint64) {
    binary.LittleEndian.PutUint64(b.seqNumData(), seqNum)
}

func (b *Batch) seqNum() uint64 {
    return binary.LittleEndian.Uint64(b.seqNumData())
}

func (b *Batch) count() uint32 {
    return binary.LittleEndian.Uint32(b.countData())
}

// 返回迭代器
func (b *Batch) iter() batchIter {
    return b.data[batchHeaderLen:]
}

type batchIter []byte

// next returns the next operation in this batch.
// The final return value is false if the batch is corrupt.
func (t *batchIter) next() (kind internalKeyKind, ukey []byte, value []byte, ok bool) {
    p := *t
    if len(p) == 0 {
        return 0, nil, nil, false
    }
    kind, *t = internalKeyKind(p[0]), p[1:]
    if kind > internalKeyKindMax {
        return 0, nil, nil, false
    }
    ukey, ok = t.nextStr()
    if !ok {
        return 0, nil, nil, false
    }
    if kind != internalKeyKindDelete {
        value, ok = t.nextStr()
        if !ok {
            return 0, nil, nil, false
        }
    }
    return kind, ukey, value, true
}

func (t *batchIter) nextStr() (s []byte, ok bool) {
    p := *t
    u, numBytes := binary.Uvarint(p)
    if numBytes <= 0 {
        return nil, false
    }
    p = p[numBytes:] //
    if u > uint64(len(p)) {
        return nil, false
    }
    s, *t = p[:u], p[u:]
    return s, true
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末牙寞,一起剝皮案震驚了整個(gè)濱河市罐氨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌态鳖,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矢渊,死亡現(xiàn)場離奇詭異舰讹,居然都是意外死亡北苟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門怕篷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來历筝,“玉大人,你說我怎么就攤上這事廊谓∈嶂恚” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵蒸痹,是天一觀的道長春弥。 經(jīng)常有香客問我,道長叠荠,這世上最難降的妖魔是什么匿沛? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮榛鼎,結(jié)果婚禮上逃呼,老公的妹妹穿的比我還像新娘。我一直安慰自己者娱,他們只是感情好蜘渣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肺然,像睡著了一般蔫缸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上际起,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天拾碌,我揣著相機(jī)與錄音,去河邊找鬼街望。 笑死校翔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灾前。 我是一名探鬼主播防症,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼娇豫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了博脑?” 一聲冷哼從身側(cè)響起驻谆,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奈嘿,沒想到半個(gè)月后貌虾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裙犹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年尽狠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叶圃。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袄膏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掺冠,到底是詐尸還是另有隱情哩陕,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布赫舒,位于F島的核電站悍及,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏接癌。R本人自食惡果不足惜心赶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缺猛。 院中可真熱鬧缨叫,春花似錦、人聲如沸荔燎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽有咨。三九已至琐簇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間座享,已是汗流浹背婉商。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渣叛,地道東北人丈秩。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像淳衙,于是被迫代替她去往敵國和親蘑秽。 傳聞我的和親對象是個(gè)殘疾皇子饺著,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 潛能營第三課,易仁永澄老師帶來他的目標(biāo)管理肠牲。課程內(nèi)容落地實(shí)用幼衰,直達(dá)核心。下面是我課后復(fù)盤的手繪導(dǎo)圖~ 課程內(nèi)容很多...
  • 文/子兔君 第一幅小清新畫作埂材。 我喜歡深夜作畫塑顺,夜靜到可以聽得見畫里生命的渴望汤求。 與之對話俏险。 你從哪來?要到哪去扬绪?...
    子兔君閱讀 234評論 4 7
  • (感觸賦) 文/菊 小弟芳年剛五旬竖独, 英年早逝碎吾心; 蒼涼經(jīng)世萬八日挤牛, 疾患纏身苦命人莹痢。 日薄西山春逝去, 不公...
    斌之志閱讀 1,687評論 30 30