一个巧妙的迭代器

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
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容

  • 潜能营第三课,易仁永澄老师带来他的目标管理。课程内容落地实用,直达核心。下面是我课后复盘的手绘导图~ 课程内容很多...
    李楠_思维导图高效学习阅读 190评论 0 2
  • 文/子兔君 第一幅小清新画作。 我喜欢深夜作画,夜静到可以听得见画里生命的渴望。 与之对话。 你从哪来?要到哪去?...
    子兔君阅读 228评论 4 7
  • (感触赋) 文/菊 小弟芳年刚五旬, 英年早逝碎吾心; 苍凉经世万八日, 疾患缠身苦命人。 日薄西山春逝去, 不公...
    斌之志阅读 1,673评论 30 30