mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
541 lines
22 KiB
Go
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
|
|
}
|