1
0
Fork 0

Remove obsolete V2 snapshot files

master
Philip O'Toole 1 year ago
parent ad3a29de16
commit 3ff1d87120

@ -1,154 +0,0 @@
package snapshot
import (
"compress/gzip"
"fmt"
"io"
"os"
)
const (
RqliteHeaderVersionSize = 32
RqliteHeaderReservedSize = 32
RqliteSnapshotVersion2 = "rqlite snapshot version 2"
)
// FileIsV2Snapshot returns true if the given path is a V2 snapshot.
func FileIsV2Snapshot(path string) bool {
file, err := os.Open(path)
if err != nil {
return false
}
defer file.Close()
return ReaderIsV2Snapshot(file)
}
// ReaderIsV2Snapshot returns true if the given reader is a V2 snapshot.
// The reader will be advanced 1 byte passed the end of the Version header.
func ReaderIsV2Snapshot(r io.Reader) bool {
header := make([]byte, RqliteHeaderVersionSize)
if _, err := io.ReadFull(r, header); err != nil {
return false
}
return string(header[:len(RqliteSnapshotVersion2)]) == RqliteSnapshotVersion2
}
// V2Encoder creates a new V2 snapshot.
type V2Encoder struct {
path string
}
// NewV2Encoder returns an initialized V2 encoder
func NewV2Encoder(path string) *V2Encoder {
return &V2Encoder{
path: path,
}
}
// WriteTo writes the snapshot to the given writer. Returns the number
// of bytes written, or an error.
func (v *V2Encoder) WriteTo(w io.Writer) (int64, error) {
file, err := os.Open(v.path)
if err != nil {
return 0, err
}
defer file.Close()
// Wrap w in counting writer.
cw := &CountingWriter{Writer: w}
if _, err := writeString(cw, RqliteSnapshotVersion2, RqliteHeaderVersionSize); err != nil {
return 0, err
}
// Write reserved space.
if _, err = cw.Write(make([]byte, RqliteHeaderReservedSize)); err != nil {
return cw.Count, err
}
gw, err := gzip.NewWriterLevel(cw, gzip.BestSpeed)
if err != nil {
return cw.Count, err
}
defer gw.Close()
if _, err := io.Copy(gw, file); err != nil {
return cw.Count, err
}
// We're done.
if err := gw.Close(); err != nil {
return cw.Count, err
}
if err := file.Close(); err != nil {
return cw.Count, err
}
return cw.Count, nil
}
// V2Decoder reads a V2 snapshot.
type V2Decoder struct {
r io.Reader
}
// NewV2Decoder returns an initialized V2 decoder
func NewV2Decoder(r io.Reader) *V2Decoder {
return &V2Decoder{
r: r,
}
}
// WriteTo writes the decoded snapshot data to the given writer.
func (v *V2Decoder) WriteTo(w io.Writer) (int64, error) {
if !ReaderIsV2Snapshot(v.r) {
return 0, fmt.Errorf("data is not a V2 snapshot")
}
// Read the reserved space and discard.
reserved := make([]byte, RqliteHeaderReservedSize)
if _, err := io.ReadFull(v.r, reserved); err != nil {
return 0, fmt.Errorf("failed to read reserved space: %w", err)
}
gr, err := gzip.NewReader(v.r)
if err != nil {
return 0, err
}
defer gr.Close()
// Decompress the database.
n, err := io.Copy(w, gr)
if err != nil {
return 0, fmt.Errorf("failed to write data: %w", err)
}
return n, err
}
// function which takes a writer, a string, and a length. If the string is longer
// than the length return an error. Otherwise string the string to the writer and
// fil the remain space up to the lnegth with 0.
func writeString(w io.Writer, s string, l int) (int, error) {
if len(s) >= l {
return 0, fmt.Errorf("string too long (%d, %d)", len(s), l)
}
if _, err := w.Write([]byte(s)); err != nil {
return 0, err
}
return w.Write(make([]byte, l-len(s)))
}
// CountingWriter counts the number of bytes written to it.
type CountingWriter struct {
Writer io.Writer
Count int64
}
// Write writes to the underlying writer and counts the number of bytes written.
func (cw *CountingWriter) Write(p []byte) (int, error) {
n, err := cw.Writer.Write(p)
cw.Count += int64(n)
return n, err
}

@ -1,120 +0,0 @@
package snapshot
import (
"bytes"
"crypto/rand"
"io"
"os"
"testing"
)
// Test_V1Encoder_WriteTo tests that the V1Encoder.WriteTo method
// writes a valid Snapshot to the given io.Writer.
func Test_V2Encoder_WriteTo(t *testing.T) {
testFilePath := makeTempFile(t)
defer os.Remove(testFilePath)
// Create V2Encoder with a test file path
v := NewV2Encoder(testFilePath)
// Create a buffer to serve as the io.Writer
buf := new(bytes.Buffer)
// Write a snapshot to the buffer
_, err := v.WriteTo(buf)
if err != nil {
t.Fatalf("Unexpected error in WriteTo: %v", err)
}
// Make a reader from the buffer
r := bytes.NewReader(buf.Bytes())
// Now sanity check the snapshot.
if !ReaderIsV2Snapshot(r) {
t.Fatalf("ReaderIsV2Snapshot returned false for valid snapshot")
}
// Write the Snapshot to a temp file.
tempSnapshotPath := makeTempFile(t)
defer os.Remove(tempSnapshotPath)
if err := os.WriteFile(tempSnapshotPath, buf.Bytes(), 0644); err != nil {
t.Fatalf("Error writing temp file: %v", err)
}
if !FileIsV2Snapshot(tempSnapshotPath) {
t.Fatalf("FileIsV2Snapshot returned false for valid snapshot")
}
}
// Test_V1Encoder_WriteToNoFile tests that the V1Encoder.WriteTo method
// returns an error when the given file does not exist.
func Test_V2Encoder_WriteToNoFile(t *testing.T) {
v := NewV2Encoder("/does/not/exist")
_, err := v.WriteTo(new(bytes.Buffer))
if err == nil {
t.Fatalf("Expected error in WriteTo due to non-existent file, but got nil")
}
}
func Test_V2SnapshotEncodeDecode(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "test-file")
if err != nil {
t.Fatalf("Error creating temp file: %v", err)
}
const size = 1024
_, err = io.CopyN(f, rand.Reader, size)
if err != nil {
t.Fatal(err)
}
f.Close()
// Encode it as a v2 snapshot to a byte buffer.
var buf bytes.Buffer
enc := NewV2Encoder(f.Name())
n, err := enc.WriteTo(&buf)
if err != nil {
t.Fatal(err)
}
// Check that `n` matches the number of bytes in the buffer.
if n != int64(buf.Len()) {
t.Fatalf("expected %d bytes, got %d", n, buf.Len())
}
// Pass the byte buffer to a decoder.
dec := NewV2Decoder(&buf)
// Have it decode the snapshot to a second byte buffer.
var decodeBuf bytes.Buffer
_, err = dec.WriteTo(&decodeBuf)
if err != nil {
t.Fatal(err)
}
// Check that we get the original contents back.
f, err = os.Open(f.Name())
if err != nil {
t.Fatal(err)
}
defer f.Close()
var originalBuf bytes.Buffer
_, err = io.Copy(&originalBuf, f)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(originalBuf.Bytes(), decodeBuf.Bytes()) {
t.Fatal("original file content and decoded content are not the same")
}
}
func makeTempFile(t *testing.T) string {
f, err := os.CreateTemp(t.TempDir(), "test-file")
if err != nil {
t.Fatalf("Error creating temp file: %v", err)
}
defer f.Close()
return f.Name()
}
Loading…
Cancel
Save