cubefs/depends/tiglabs/raft/storage/wal/log_file_test.go
leonrayang 9a30b9f884 update: update to CubeFS
Signed-off-by: leonrayang <chl696@sina.com>
2022-08-22 18:16:09 +08:00

541 lines
22 KiB
Go

// Copyright 2021 The CubeFS Authors.
//
// 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.
package wal
import (
"fmt"
"io/ioutil"
"os"
"path"
"testing"
"github.com/cubefs/cubefs/depends/tiglabs/raft/proto"
)
// This test case is used to test the process logic of LogEntryFile for file fault
// tolerance when loading a damaged log file.
func TestAutoFixLastIndexLogEntryFile_BrokenLogEntry(t *testing.T) {
var err error
var testPath = path.Join(os.TempDir(), "test_auto_fix_broken_log_entry_file")
if err = os.MkdirAll(testPath, os.ModePerm); err != nil {
t.Fatalf("prepare test path fail: %v", err)
}
defer func() {
_ = os.RemoveAll(testPath)
}()
type __sample struct {
Desc string // Sample description
FileData []byte // Sample log file data
Entries []*proto.Entry // Expected valid entries
FirstIndex uint64 // Expected first index
LastIndex uint64 // Expected last index
}
var (
samples = []*__sample{
{
Desc: "complete log file",
FileData: []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x43, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a,
0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a,
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0xf0,
0xdf, 0xd9, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x44, 0x7b, 0x22, 0x6f,
0x70, 0x22, 0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22,
0x76, 0x22, 0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d,
0x22, 0x7d, 0x05, 0x02, 0x5b, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x45,
0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x38, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c,
0x2c, 0x22, 0x76, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x27, 0x93, 0x59, 0x23, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x46, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x32, 0x35,
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0x85, 0x81, 0x69,
0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x47, 0x7b, 0x22, 0x6f, 0x70, 0x22,
0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22,
0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d,
0x45, 0x41, 0xe4, 0xac,
},
Entries: []*proto.Entry{
{Index: 165699, Term: 369},
{Index: 165700, Term: 369},
{Index: 165701, Term: 369},
{Index: 165702, Term: 369},
{Index: 165703, Term: 369},
},
FirstIndex: 165699,
LastIndex: 165703,
},
{
Desc: "broken tail log file",
FileData: []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x43, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a,
0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a,
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0xf0,
0xdf, 0xd9, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x44, 0x7b, 0x22, 0x6f,
0x70, 0x22, 0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22,
0x76, 0x22, 0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d,
0x22, 0x7d, 0x05, 0x02, 0x5b, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x45,
0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x38, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c,
0x2c, 0x22, 0x76, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x27, 0x93, 0x59, 0x23, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x46, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x32, 0x35,
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0x85, 0x81, 0x69,
0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x47, 0x7b, 0x22, 0x6f, 0x70, 0x22,
0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22,
0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d,
0x45, 0x41, 0xe4, 0x00, // <- The broken byte here
},
Entries: []*proto.Entry{
{Index: 165699, Term: 369},
{Index: 165700, Term: 369},
{Index: 165701, Term: 369},
{Index: 165702, Term: 369},
},
FirstIndex: 165699,
LastIndex: 165702,
},
{
Desc: "broken tail log file (missing last one byte)",
FileData: []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x43, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a,
0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a,
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0xf0,
0xdf, 0xd9, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x44, 0x7b, 0x22, 0x6f,
0x70, 0x22, 0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22,
0x76, 0x22, 0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d,
0x22, 0x7d, 0x05, 0x02, 0x5b, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x45,
0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x38, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c,
0x2c, 0x22, 0x76, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x27, 0x93, 0x59, 0x23, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x46, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x32, 0x35,
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0x85, 0x81, 0x69,
0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x47, 0x7b, 0x22, 0x6f, 0x70, 0x22,
0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22,
0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d,
0x45, 0x41, 0xe4, // <- Missing last one byte.
},
Entries: []*proto.Entry{
{Index: 165699, Term: 369},
{Index: 165700, Term: 369},
{Index: 165701, Term: 369},
{Index: 165702, Term: 369},
},
FirstIndex: 165699,
LastIndex: 165702,
},
{
Desc: "broken head log file",
FileData: []byte{
// The first byte is corrupted
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x43, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a,
0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a,
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0xf0,
0xdf, 0xd9, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x44, 0x7b, 0x22, 0x6f,
0x70, 0x22, 0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22,
0x76, 0x22, 0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d,
0x22, 0x7d, 0x05, 0x02, 0x5b, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x45,
0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x38, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c,
0x2c, 0x22, 0x76, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x27, 0x93, 0x59, 0x23, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x46, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x32, 0x35,
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0x85, 0x81, 0x69,
0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x47, 0x7b, 0x22, 0x6f, 0x70, 0x22,
0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22,
0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d,
0x45, 0x41, 0xe4, 0xac,
},
Entries: []*proto.Entry{},
FirstIndex: 0,
LastIndex: 0,
},
{
Desc: "broken middle log file",
FileData: []byte{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x43, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a,
0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a,
0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0xf0,
0xdf, 0xd9, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x44, 0x7b, 0x22, 0x6f,
0x70, 0x22, 0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22,
0x76, 0x22, 0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d,
0x22, 0x7d, 0x05, 0x02, 0x5b, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x45,
0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x38, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x00, // <- The broken byte here
0x2c, 0x22, 0x76, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x27, 0x93, 0x59, 0x23, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x46, 0x7b, 0x22, 0x6f, 0x70, 0x22, 0x3a, 0x32, 0x35,
0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22, 0x3a, 0x22, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d, 0x85, 0x81, 0x69,
0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x87, 0x47, 0x7b, 0x22, 0x6f, 0x70, 0x22,
0x3a, 0x32, 0x35, 0x2c, 0x22, 0x6b, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x76, 0x22,
0x3a, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x73, 0x41, 0x41, 0x51, 0x30, 0x3d, 0x22, 0x7d,
0x45, 0x41, 0xe4, 0xac,
},
Entries: []*proto.Entry{
{Index: 165699, Term: 369},
{Index: 165700, Term: 369},
},
FirstIndex: 165699,
LastIndex: 165700,
},
}
testLogFileName = "0000000000000000-0000000000000001.log"
)
for _, sample := range samples {
// Prepare test data and write it to test log file.
if err = ioutil.WriteFile(path.Join(testPath, testLogFileName), sample.FileData, os.ModePerm); err != nil {
t.Fatalf("[%v] prepare test file data fail: %v", sample.Desc, err)
}
// Load test log file
logFileName := logFileName{}
logFileName.ParseFrom(testLogFileName)
for testCount := 1; testCount <= 3; testCount++ {
var lf *logEntryFile
if lf, err = openLogEntryFile(
testPath,
logFileName,
true); err != nil {
t.Fatalf("[%v %v] open test log file fail: %v", sample.Desc, testCount, err)
}
// Validate first index
fi := lf.FirstIndex()
if fi != sample.FirstIndex {
t.Fatalf("[%v %v] first index mismatch: expect %v, actual %v", sample.Desc, testCount, sample.FirstIndex, fi)
}
// Validate last index
li := lf.LastIndex()
if li != sample.LastIndex {
t.Fatalf("[%v %v] last index mismatch: expect %v, actual %v", sample.Desc, testCount, sample.LastIndex, li)
}
// Validate each log entry
var e *proto.Entry
var entryIndex = 0
for i := fi; i > 0 && i <= li; i++ {
if e, err = lf.Get(i); err != nil {
t.Fatalf("[%v %v] get log entry fail: index %v, %v", sample.Desc, testCount, i, err)
}
var sampleEntry = sample.Entries[entryIndex]
if e.Index != sampleEntry.Index || e.Term != sampleEntry.Term || e.Type != sampleEntry.Type {
t.Fatalf("[%v %v] entry data mismatch: expact %v, actual %v",
sample.Desc, testCount,
fmt.Sprintf("%v_%v_%v", sampleEntry.Index, sampleEntry.Term, sampleEntry.Type),
fmt.Sprintf("%v_%v_%v", e.Index, e.Term, e.Type))
}
entryIndex++
}
_ = lf.Close()
}
_ = os.Remove(path.Join(testPath, testLogFileName))
}
}
func TestAutoFixLastIndexLogEntryFile_BrokenIndex_MissingLastOneByte(t *testing.T) {
var err error
var testPath = path.Join(os.TempDir(), "test_auto_fix_broken_index_log_entry_file")
if err = os.MkdirAll(testPath, os.ModePerm); err != nil {
t.Fatalf("prepare test path fail: %v", err)
}
defer func() {
_ = os.RemoveAll(testPath)
}()
var (
sampleEntries = []*proto.Entry{
{Term: 1, Index: 1},
{Term: 1, Index: 2},
{Term: 1, Index: 3},
{Term: 1, Index: 4},
}
firstIndex uint64 = 1
lastIndex uint64 = 4
testLogFileName = "0000000000000000-0000000000000001.log"
)
// Prepare test log file
if err = generateLogEntryFileWithIndex(testPath, testLogFileName, sampleEntries); err != nil {
return
}
// Truncate last byte
var info os.FileInfo
if info, err = os.Stat(path.Join(testPath, testLogFileName)); err != nil {
t.Fatalf("stat test log file fail: %v", err)
}
if info.Size() == 0 {
t.Fatalf("test log file size is 0")
}
if err = os.Truncate(path.Join(testPath, testLogFileName), info.Size()-1); err != nil {
t.Fatalf("truncate test log file fail: %v", err)
}
// Load and validate log file
logFileName := logFileName{}
logFileName.ParseFrom(testLogFileName)
for testCount := 1; testCount <= 3; testCount++ {
var lf *logEntryFile
if lf, err = openLogEntryFile(
testPath,
logFileName,
true); err != nil {
t.Fatalf("open test log file fail: %v", err)
}
// Validate first index
fi := lf.FirstIndex()
if fi != firstIndex {
t.Fatalf("first index mismatch: expect %v, actual %v", firstIndex, fi)
}
// Validate last index
li := lf.LastIndex()
if li != lastIndex {
t.Fatalf("last index mismatch: expect %v, actual %v", lastIndex, li)
}
// Validate each log entry
var e *proto.Entry
var entryIndex = 0
for i := fi; i > 0 && i <= li; i++ {
if e, err = lf.Get(i); err != nil {
t.Fatalf("get log entry fail: index %v, %v", i, err)
}
var sampleEntry = sampleEntries[entryIndex]
if e.Index != sampleEntry.Index || e.Term != sampleEntry.Term || e.Type != sampleEntry.Type {
t.Fatalf("entry data mismatch: expact %v, actual %v",
fmt.Sprintf("%v_%v_%v", sampleEntry.Index, sampleEntry.Term, sampleEntry.Type),
fmt.Sprintf("%v_%v_%v", e.Index, e.Term, e.Type))
}
entryIndex++
}
_ = lf.Close()
}
}
func TestAutoFixLastIndexLogEntryFile_BrokenIndex_BrokenLastOneByte(t *testing.T) {
var err error
var testPath = path.Join(os.TempDir(), "test_auto_fix_broken_index_log_entry_file")
if err = os.MkdirAll(testPath, os.ModePerm); err != nil {
t.Fatalf("prepare test path fail: %v", err)
}
defer func() {
_ = os.RemoveAll(testPath)
}()
var (
sampleEntries = []*proto.Entry{
{Term: 1, Index: 1},
{Term: 1, Index: 2},
{Term: 1, Index: 3},
{Term: 1, Index: 4},
}
firstIndex uint64 = 1
lastIndex uint64 = 4
testLogFileName = "0000000000000000-0000000000000001.log"
)
// Prepare test log file
if err = generateLogEntryFileWithIndex(testPath, testLogFileName, sampleEntries); err != nil {
return
}
// Overwrite last one byte
var f *os.File
if f, err = os.OpenFile(path.Join(testPath, testLogFileName), os.O_RDWR, os.ModePerm); err != nil {
t.Fatalf("open log file fail: %v", err)
}
var stat os.FileInfo
if stat, err = f.Stat(); err != nil {
t.Fatalf("stat log file fail: %v", err)
}
if _, err = f.WriteAt([]byte{0xff}, stat.Size()-1); err != nil {
t.Fatalf("overwrite log file fail: %v", err)
}
_ = f.Sync()
_ = f.Close()
// Load and validate log file
logFileName := logFileName{}
logFileName.ParseFrom(testLogFileName)
for testCount := 1; testCount <= 3; testCount++ {
var lf *logEntryFile
if lf, err = openLogEntryFile(
testPath,
logFileName,
true); err != nil {
t.Fatalf("open test log file fail: %v", err)
}
// Validate first index
fi := lf.FirstIndex()
if fi != firstIndex {
t.Fatalf("first index mismatch: expect %v, actual %v", firstIndex, fi)
}
// Validate last index
li := lf.LastIndex()
if li != lastIndex {
t.Fatalf("last index mismatch: expect %v, actual %v", lastIndex, li)
}
// Validate each log entry
var e *proto.Entry
var entryIndex = 0
for i := fi; i > 0 && i <= li; i++ {
if e, err = lf.Get(i); err != nil {
t.Fatalf("get log entry fail: index %v, %v", i, err)
}
var sampleEntry = sampleEntries[entryIndex]
if e.Index != sampleEntry.Index || e.Term != sampleEntry.Term || e.Type != sampleEntry.Type {
t.Fatalf("entry data mismatch: expact %v, actual %v",
fmt.Sprintf("%v_%v_%v", sampleEntry.Index, sampleEntry.Term, sampleEntry.Type),
fmt.Sprintf("%v_%v_%v", e.Index, e.Term, e.Type))
}
entryIndex++
}
_ = lf.Close()
}
}
func TestAutoFixLastIndexLogEntryFile_BrokenIndex_OneMoreByteAtTheEnd(t *testing.T) {
var err error
var testPath = path.Join(os.TempDir(), "test_auto_fix_broken_index_log_entry_file")
if err = os.MkdirAll(testPath, os.ModePerm); err != nil {
t.Fatalf("prepare test path fail: %v", err)
}
defer func() {
_ = os.RemoveAll(testPath)
}()
var (
sampleEntries = []*proto.Entry{
{Term: 1, Index: 1},
{Term: 1, Index: 2},
{Term: 1, Index: 3},
{Term: 1, Index: 4},
}
firstIndex uint64 = 1
lastIndex uint64 = 4
testLogFileName = "0000000000000000-0000000000000001.log"
)
// Prepare test log file
if err = generateLogEntryFileWithIndex(testPath, testLogFileName, sampleEntries); err != nil {
return
}
// Append one garbage byte to log file
var f *os.File
if f, err = os.OpenFile(path.Join(testPath, testLogFileName), os.O_RDWR|os.O_APPEND, os.ModePerm); err != nil {
t.Fatalf("append garbage byte to log file fail: %v", err)
}
if _, err = f.Write([]byte{0x00}); err != nil {
t.Fatalf("append garbage byte to log file fail: %v", err)
}
_ = f.Sync()
_ = f.Close()
// Load and validate log file
logFileName := logFileName{}
logFileName.ParseFrom(testLogFileName)
for testCount := 1; testCount <= 3; testCount++ {
var lf *logEntryFile
if lf, err = openLogEntryFile(
testPath,
logFileName,
true); err != nil {
t.Fatalf("open test log file fail: %v", err)
}
// Validate first index
fi := lf.FirstIndex()
if fi != firstIndex {
t.Fatalf("first index mismatch: expect %v, actual %v", firstIndex, fi)
}
// Validate last index
li := lf.LastIndex()
if li != lastIndex {
t.Fatalf("last index mismatch: expect %v, actual %v", lastIndex, li)
}
// Validate each log entry
var e *proto.Entry
var entryIndex = 0
for i := fi; i > 0 && i <= li; i++ {
if e, err = lf.Get(i); err != nil {
t.Fatalf("get log entry fail: index %v, %v", i, err)
}
var sampleEntry = sampleEntries[entryIndex]
if e.Index != sampleEntry.Index || e.Term != sampleEntry.Term || e.Type != sampleEntry.Type {
t.Fatalf("entry data mismatch: expact %v, actual %v",
fmt.Sprintf("%v_%v_%v", sampleEntry.Index, sampleEntry.Term, sampleEntry.Type),
fmt.Sprintf("%v_%v_%v", e.Index, e.Term, e.Type))
}
entryIndex++
}
_ = lf.Close()
}
}
func generateLogEntryFileWithIndex(path, name string, entries []*proto.Entry) (err error) {
logFileName := logFileName{}
logFileName.ParseFrom(name)
var lf *logEntryFile
if lf, err = createLogEntryFile(path, logFileName); err != nil {
return
}
for _, entry := range entries {
if err = lf.Save(entry); err != nil {
return
}
}
if err = lf.FinishWrite(); err != nil {
return
}
err = lf.Close()
return
}