From 6696b36dc85177d145e12bfb4c38ee6a4830be25 Mon Sep 17 00:00:00 2001 From: Sean Farley Date: Mon, 13 Mar 2017 13:57:13 -0400 Subject: [PATCH] Add DumpN() functions --- cdb.go | 39 +++++++++++++++++++++++++++++++++++++++ dump.go | 32 +++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/cdb.go b/cdb.go index e87094a..1215a4d 100644 --- a/cdb.go +++ b/cdb.go @@ -74,6 +74,45 @@ func (c *Cdb) Data(key []byte) (data []byte, err error) { return } +// DumpN returns n records, starting at record number o, from the cdb as an +// array of [2][]byte values: key, data. +// If n is 0, then all of the records are returned. +func (c *Cdb) DumpN(n uint64, o uint64) (recs [][2][]byte) { + intBuf := make([]byte, 4) + pos := uint32(0) + readNum := func () uint32 { + c.r.ReadAt(intBuf, int64(pos)) + pos += 4 + return binary.LittleEndian.Uint32(intBuf) + } + + eod := readNum() + pos = headerSize // skip header + recNum := uint64(0) + for pos < eod && (n == 0 || recNum < n) { + // CDB records are laid out as: [klen (uint32)] [dlen (uint32)] [key (klen bytes)] [data (dlen bytes)] + klen := readNum() + dlen := readNum() + if recNum >= o { + // read key and data: + k := make([]byte, klen) + d := make([]byte, dlen) + c.r.ReadAt(k, int64(pos)) + pos += klen + c.r.ReadAt(d, int64(pos)) + pos += dlen + recs = append(recs, [2][]byte{k, d}) + } else { + // skip: + pos += klen + dlen + } + + recNum++ + } + + return +} + // FindStart resets the cdb to search for the first record under a new key. func (c *Cdb) FindStart() { c.loop = 0 } diff --git a/dump.go b/dump.go index 6772cd2..5cfca1b 100644 --- a/dump.go +++ b/dump.go @@ -7,11 +7,21 @@ import ( "io" ) -// Dump reads the cdb-formatted data in r and dumps it as a series of formatted -// records (+klen,dlen:key->data\n) and a final newline to w. +// Dump reads records from the cdb-formatted data in r and dumps it as a +// series of formatted records (+klen,dlen:key->data\n) and a final newline to w. // The output of Dump is suitable as input to Make. // See http://cr.yp.to/cdb/cdbmake.html for details on the record format. -func Dump(w io.Writer, r io.Reader) (err error) { +func Dump(w io.Writer, r io.Reader) error { + return DumpN(0, 0, w, r) +} + +// DumpN reads n records, starting at record number o, from the cdb-formatted +// data in r and dumps it as a series of formatted records +// (+klen,dlen:key->data\n) and a final newline to w. +// If n is 0, then all of the records are dumped. +// The output of DumpN is suitable as input to Make. +// See http://cr.yp.to/cdb/cdbmake.html for details on the record format. +func DumpN(n uint64, o uint64, w io.Writer, r io.Reader) (err error) { defer func() { // Centralize exception handling. if e := recover(); e != nil { err = e.(error) @@ -29,14 +39,18 @@ func Dump(w io.Writer, r io.Reader) (err error) { } pos := headerSize - for pos < eod { + recNum := uint64(0) + for pos < eod && (n == 0 || recNum < n) { klen, dlen := readNum(), readNum() - rw.writeString(fmt.Sprintf("+%d,%d:", klen, dlen)) - rw.copyn(rb, klen) - rw.writeString("->") - rw.copyn(rb, dlen) - rw.writeString("\n") + if recNum >= o { + rw.writeString(fmt.Sprintf("+%d,%d:", klen, dlen)) + rw.copyn(rb, klen) + rw.writeString("->") + rw.copyn(rb, dlen) + rw.writeString("\n") + } pos += 8 + klen + dlen + recNum++ } rw.writeString("\n")