Files
dolt/go/store/chunks/chunk_serializer.go
T

114 lines
2.8 KiB
Go

// Copyright 2019 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file incorporates work covered by the following copyright and
// permission notice:
//
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
package chunks
import (
"bytes"
"encoding/binary"
"io"
"github.com/dolthub/dolt/go/store/d"
"github.com/dolthub/dolt/go/store/hash"
)
/*
Chunk Serialization:
Chunk 0
Chunk 1
..
Chunk N
Chunk:
Hash // 20-byte hash
Len // 4-byte int
Data // len(Data) == Len
*/
// Serialize a single Chunk to writer.
func Serialize(chunk Chunk, writer io.Writer) {
d.PanicIfFalse(chunk.data != nil)
h := chunk.Hash()
n, err := io.Copy(writer, bytes.NewReader(h[:]))
d.Chk.NoError(err)
d.PanicIfFalse(int64(hash.ByteLen) == n)
// Because of chunking at higher levels, no chunk should never be more than 4GB
chunkSize := uint32(len(chunk.Data()))
err = binary.Write(writer, binary.BigEndian, chunkSize)
d.Chk.NoError(err)
n, err = io.Copy(writer, bytes.NewReader(chunk.Data()))
d.Chk.NoError(err)
d.PanicIfFalse(uint32(n) == chunkSize)
}
// Deserialize reads off of |reader| until EOF, sending chunks to
// chunkChan in the order they are read. Objects sent over chunkChan are
// *Chunk.
func Deserialize(reader io.Reader, chunkChan chan<- *Chunk) (err error) {
for {
var c Chunk
c, err = deserializeChunk(reader)
if err != nil {
break
}
d.Chk.NotEqual(EmptyChunk.Hash(), c.Hash())
chunkChan <- &c
}
if err == io.EOF {
err = nil
}
return
}
// DeserializeData deserializes a chunk from a byte array
func DeserializeData(data []byte) (Chunk, error) {
reader := bytes.NewReader(data)
return deserializeChunk(reader)
}
func deserializeChunk(reader io.Reader) (Chunk, error) {
h := hash.Hash{}
n, err := io.ReadFull(reader, h[:])
if err != nil {
return EmptyChunk, err
}
d.PanicIfFalse(int(hash.ByteLen) == n)
chunkSize := uint32(0)
if err = binary.Read(reader, binary.BigEndian, &chunkSize); err != nil {
return EmptyChunk, err
}
data := make([]byte, int(chunkSize))
if n, err = io.ReadFull(reader, data); err != nil {
return EmptyChunk, err
}
d.PanicIfFalse(int(chunkSize) == n)
c := NewChunk(data)
if h != c.Hash() {
d.Panic("%s != %s", h, c.Hash().String())
}
return c, nil
}