github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/manifest/version_edit_test.go (about)

     1  // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package manifest
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/kr/pretty"
    18  	"github.com/petermattis/pebble/internal/base"
    19  	"github.com/petermattis/pebble/internal/record"
    20  )
    21  
    22  func checkRoundTrip(e0 VersionEdit) error {
    23  	var e1 VersionEdit
    24  	buf := new(bytes.Buffer)
    25  	if err := e0.Encode(buf); err != nil {
    26  		return fmt.Errorf("encode: %v", err)
    27  	}
    28  	if err := e1.Decode(buf); err != nil {
    29  		return fmt.Errorf("decode: %v", err)
    30  	}
    31  	if !reflect.DeepEqual(e1, e0) {
    32  		return fmt.Errorf("\n\tgot  %#v\n\twant %#v", e1, e0)
    33  	}
    34  	return nil
    35  }
    36  
    37  func TestVersionEditRoundTrip(t *testing.T) {
    38  	testCases := []VersionEdit{
    39  		// An empty version edit.
    40  		{},
    41  		// A complete version edit.
    42  		{
    43  			ComparerName: "11",
    44  			LogNum:       22,
    45  			PrevLogNum:   33,
    46  			NextFileNum:  44,
    47  			LastSeqNum:   55,
    48  			DeletedFiles: map[DeletedFileEntry]bool{
    49  				DeletedFileEntry{
    50  					Level:   3,
    51  					FileNum: 703,
    52  				}: true,
    53  				DeletedFileEntry{
    54  					Level:   4,
    55  					FileNum: 704,
    56  				}: true,
    57  			},
    58  			NewFiles: []NewFileEntry{
    59  				{
    60  					Level: 5,
    61  					Meta: FileMetadata{
    62  						FileNum:  805,
    63  						Size:     8050,
    64  						Smallest: base.DecodeInternalKey([]byte("abc\x00\x01\x02\x03\x04\x05\x06\x07")),
    65  						Largest:  base.DecodeInternalKey([]byte("xyz\x01\xff\xfe\xfd\xfc\xfb\xfa\xf9")),
    66  					},
    67  				},
    68  				{
    69  					Level: 6,
    70  					Meta: FileMetadata{
    71  						FileNum:             806,
    72  						Size:                8060,
    73  						Smallest:            base.DecodeInternalKey([]byte("A\x00\x01\x02\x03\x04\x05\x06\x07")),
    74  						Largest:             base.DecodeInternalKey([]byte("Z\x01\xff\xfe\xfd\xfc\xfb\xfa\xf9")),
    75  						SmallestSeqNum:      3,
    76  						LargestSeqNum:       5,
    77  						MarkedForCompaction: true,
    78  					},
    79  				},
    80  			},
    81  		},
    82  	}
    83  	for _, tc := range testCases {
    84  		if err := checkRoundTrip(tc); err != nil {
    85  			t.Error(err)
    86  		}
    87  	}
    88  }
    89  
    90  func TestVersionEditDecode(t *testing.T) {
    91  	testCases := []struct {
    92  		filename     string
    93  		encodedEdits []string
    94  		edits        []VersionEdit
    95  	}{
    96  		// db-stage-1 and db-stage-2 have the same manifest.
    97  		{
    98  			filename: "db-stage-1/MANIFEST-000001",
    99  			encodedEdits: []string{
   100  				"\x02\x00\x03\x02\x04\x00",
   101  			},
   102  			edits: []VersionEdit{
   103  				{
   104  					NextFileNum: 2,
   105  				},
   106  			},
   107  		},
   108  		// db-stage-3 and db-stage-4 have the same manifest.
   109  		{
   110  			filename: "db-stage-3/MANIFEST-000005",
   111  			encodedEdits: []string{
   112  				"\x01\x1aleveldb.BytewiseComparator",
   113  				"\x02\x00",
   114  				"\x02\x04\t\x00\x03\x06\x04\x05d\x00\x04\xda\a\vbar" +
   115  					"\x00\x05\x00\x00\x00\x00\x00\x00\vfoo\x01\x04\x00" +
   116  					"\x00\x00\x00\x00\x00\x03\x05",
   117  			},
   118  			edits: []VersionEdit{
   119  				{
   120  					ComparerName: "leveldb.BytewiseComparator",
   121  				},
   122  				{},
   123  				{
   124  					LogNum:      4,
   125  					PrevLogNum:  0,
   126  					NextFileNum: 6,
   127  					LastSeqNum:  5,
   128  					NewFiles: []NewFileEntry{
   129  						{
   130  							Level: 0,
   131  							Meta: FileMetadata{
   132  								FileNum:        4,
   133  								Size:           986,
   134  								Smallest:       base.MakeInternalKey([]byte("bar"), 5, base.InternalKeyKindDelete),
   135  								Largest:        base.MakeInternalKey([]byte("foo"), 4, base.InternalKeyKindSet),
   136  								SmallestSeqNum: 3,
   137  								LargestSeqNum:  5,
   138  							},
   139  						},
   140  					},
   141  				},
   142  			},
   143  		},
   144  	}
   145  
   146  	for _, tc := range testCases {
   147  		t.Run("", func(t *testing.T) {
   148  			f, err := os.Open("../../testdata/" + tc.filename)
   149  			if err != nil {
   150  				t.Fatalf("filename=%q: open error: %v", tc.filename, err)
   151  			}
   152  			defer f.Close()
   153  			i, r := 0, record.NewReader(f, 0 /* logNum */)
   154  			for {
   155  				rr, err := r.Next()
   156  				if err == io.EOF {
   157  					break
   158  				}
   159  				if err != nil {
   160  					t.Fatalf("filename=%q i=%d: record reader error: %v", tc.filename, i, err)
   161  				}
   162  				if i >= len(tc.edits) {
   163  					t.Fatalf("filename=%q i=%d: too many version edits", tc.filename, i+1)
   164  				}
   165  
   166  				encodedEdit, err := ioutil.ReadAll(rr)
   167  				if err != nil {
   168  					t.Fatalf("filename=%q i=%d: read error: %v", tc.filename, i, err)
   169  				}
   170  				if s := string(encodedEdit); s != tc.encodedEdits[i] {
   171  					t.Fatalf("filename=%q i=%d: got encoded %q, want %q", tc.filename, i, s, tc.encodedEdits[i])
   172  				}
   173  
   174  				var edit VersionEdit
   175  				err = edit.Decode(bytes.NewReader(encodedEdit))
   176  				if err != nil {
   177  					t.Fatalf("filename=%q i=%d: decode error: %v", tc.filename, i, err)
   178  				}
   179  				if !reflect.DeepEqual(edit, tc.edits[i]) {
   180  					t.Fatalf("filename=%q i=%d: decode\n\tgot  %#v\n\twant %#v\n%s", tc.filename, i, edit, tc.edits[i],
   181  						strings.Join(pretty.Diff(edit, tc.edits[i]), "\n"))
   182  				}
   183  				if err := checkRoundTrip(edit); err != nil {
   184  					t.Fatalf("filename=%q i=%d: round trip: %v", tc.filename, i, err)
   185  				}
   186  
   187  				i++
   188  			}
   189  			if i != len(tc.edits) {
   190  				t.Fatalf("filename=%q: got %d edits, want %d", tc.filename, i, len(tc.edits))
   191  			}
   192  		})
   193  	}
   194  }