diff --git a/tools/rsync/algorithm.go b/tools/rsync/algorithm.go index 09b417f36..72c38abc9 100644 --- a/tools/rsync/algorithm.go +++ b/tools/rsync/algorithm.go @@ -44,30 +44,38 @@ type Operation struct { var bin = binary.LittleEndian -func (self Operation) Serialize() []byte { - if self.serialized_repr != nil { - return self.serialized_repr - } - var ans []byte +func (self Operation) SerializeSize() int { + switch self.Type { + case OpBlock: + return 9 + case OpBlockRange: + return 13 + case OpHash: + return 3 + len(self.Data) + case OpData: + return 5 + len(self.Data) + } + return -1 +} + +func (self Operation) Serialize(ans []byte) { + if self.serialized_repr != nil { + copy(ans, self.serialized_repr) + } switch self.Type { case OpBlock: - ans = make([]byte, 9) bin.PutUint64(ans[1:], self.BlockIndex) case OpBlockRange: - ans = make([]byte, 13) bin.PutUint64(ans[1:], self.BlockIndex) bin.PutUint32(ans[9:], uint32(self.BlockIndexEnd-self.BlockIndex)) case OpHash: - ans = make([]byte, 3+len(self.Data)) bin.PutUint16(ans[1:], uint16(len(self.Data))) copy(ans[3:], self.Data) case OpData: - ans = make([]byte, 5+len(self.Data)) bin.PutUint32(ans[1:], uint32(len(self.Data))) copy(ans[5:], self.Data) } ans[0] = byte(self.Type) - return ans } func (self *Operation) Unserialize(data []byte) (n int, err error) { diff --git a/tools/rsync/api.go b/tools/rsync/api.go index 1c6db5b53..e7700f32a 100644 --- a/tools/rsync/api.go +++ b/tools/rsync/api.go @@ -178,12 +178,12 @@ func write_block_hash(output []byte, bl BlockHash) []byte { return output } -// Append the next signature to the provided slice and return the resulting slice. Data is written to the slice iff err == nil. -// When no more signature data is available, err = io.EOF and the unmodified slice is returned. -type SignatureIterator = func([]byte) ([]byte, error) +// Append the next item to the provided slice and return the resulting slice. Data is written to the slice iff err == nil. +// When no more data is available, err = io.EOF and the unmodified slice is returned. +type OutputIterator = func([]byte) ([]byte, error) // Create a signature for the data source in src. -func (self *Patcher) CreateSignatureIterator(src io.Reader) SignatureIterator { +func (self *Patcher) CreateSignatureIterator(src io.Reader) OutputIterator { var it func() (BlockHash, error) finished := false return func(output []byte) ([]byte, error) { @@ -212,24 +212,29 @@ func (self *Patcher) CreateSignatureIterator(src io.Reader) SignatureIterator { } } -type DeltaIterator = func() ([]byte, error) - // Create a serialized delta based on the previously loaded signature -func (self *Differ) CreateDelta(src io.Reader) DeltaIterator { +func (self *Differ) CreateDelta(src io.Reader) OutputIterator { if err := self.finish_signature_data(); err != nil { - return func() ([]byte, error) { return nil, err } + return func([]byte) ([]byte, error) { return nil, err } } if self.signature == nil { - return func() ([]byte, error) { return nil, fmt.Errorf("Cannot call CreateDelta() before loading a signature") } + return func([]byte) ([]byte, error) { + return nil, fmt.Errorf("Cannot call CreateDelta() before loading a signature") + } } it := self.rsync.CreateDiff(src, self.signature) - return func() ([]byte, error) { + return func(output []byte) ([]byte, error) { for { op, err := it() if op == nil { - return nil, err + if err == nil { + err = io.EOF + } + return output, err } - return op.Serialize(), nil + output, p := ensure_size(output, op.SerializeSize()) + op.Serialize(p) + return output, nil } } } diff --git a/tools/rsync/api_test.go b/tools/rsync/api_test.go index 71d494d90..dda3d1067 100644 --- a/tools/rsync/api_test.go +++ b/tools/rsync/api_test.go @@ -96,29 +96,26 @@ func run_roundtrip_test(t *testing.T, src_data, changed []byte, num_of_patches, if err := d.AddSignatureData(signature_of_changed); err != nil { t.Fatal(err) } - deltabuf := bytes.Buffer{} + deltabuf := make([]byte, 0, 8192) it := d.CreateDelta(bytes.NewBuffer(src_data)) for { - b, err := it() - if b == nil { - if err != nil { - t.Fatal(err) + b, err := it(deltabuf) + if err != nil { + if err == io.EOF { + break } - break + t.Fatal(err) } - deltabuf.Write(b) + deltabuf = b } outputbuf := bytes.Buffer{} p.StartDelta(&outputbuf, bytes.NewReader(changed)) - b := make([]byte, 30*1024) - for { - n, _ := deltabuf.Read(b) - if n <= 0 { - break - } - if err := p.UpdateDelta(b[:n]); err != nil { + for len(deltabuf) > 0 { + n := utils.Min(123, len(deltabuf)) + if err := p.UpdateDelta(deltabuf[:n]); err != nil { t.Fatal(err) } + deltabuf = deltabuf[n:] } if err := p.FinishDelta(); err != nil { t.Fatal(err)