2016-10-07 08:22:24 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2018-06-23 23:48:19 +00:00
|
|
|
"math/rand"
|
2022-08-24 06:53:35 +00:00
|
|
|
"reflect"
|
2018-06-24 22:19:57 +00:00
|
|
|
"testing"
|
2019-05-04 00:22:39 +00:00
|
|
|
"time"
|
2019-04-19 04:43:36 +00:00
|
|
|
|
2022-07-29 07:17:28 +00:00
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/super_block"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/types"
|
2016-10-07 08:22:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
makediff test steps
|
|
|
|
1. launch weed server at your local/dev environment, (option
|
|
|
|
"garbageThreshold" for master and option "max" for volume should be set with specific value which would let
|
|
|
|
preparing test prerequisite easier )
|
|
|
|
a) ./weed master -garbageThreshold=0.99 -mdir=./m
|
|
|
|
b) ./weed volume -dir=./data -max=1 -mserver=localhost:9333 -port=8080
|
|
|
|
2. upload 4 different files, you could call dir/assign to get 4 different fids
|
|
|
|
a) upload file A with fid a
|
|
|
|
b) upload file B with fid b
|
|
|
|
c) upload file C with fid c
|
|
|
|
d) upload file D with fid d
|
|
|
|
3. update file A and C
|
|
|
|
a) modify file A and upload file A with fid a
|
|
|
|
b) modify file C and upload file C with fid c
|
|
|
|
c) record the current 1.idx's file size(lastCompactIndexOffset value)
|
|
|
|
4. Compacting the data file
|
|
|
|
a) run curl http://localhost:8080/admin/vacuum/compact?volumeId=1
|
|
|
|
b) verify the 1.cpd and 1.cpx is created under volume directory
|
|
|
|
5. update file B and delete file D
|
|
|
|
a) modify file B and upload file B with fid b
|
|
|
|
d) delete file B with fid b
|
|
|
|
6. Now you could run the following UT case, the case should be run successfully
|
|
|
|
7. Compact commit manually
|
|
|
|
a) mv 1.cpd 1.dat
|
|
|
|
b) mv 1.cpx 1.idx
|
|
|
|
8. Restart Volume Server
|
|
|
|
9. Now you should get updated file A,B,C
|
|
|
|
*/
|
|
|
|
|
|
|
|
func TestMakeDiff(t *testing.T) {
|
|
|
|
|
|
|
|
v := new(Volume)
|
2021-10-14 04:27:58 +00:00
|
|
|
// lastCompactIndexOffset value is the index file size before step 4
|
2016-10-07 08:22:24 +00:00
|
|
|
v.lastCompactIndexOffset = 96
|
2019-12-23 20:48:20 +00:00
|
|
|
v.SuperBlock.Version = 0x2
|
2016-10-07 08:40:51 +00:00
|
|
|
/*
|
|
|
|
err := v.makeupDiff(
|
|
|
|
"/yourpath/1.cpd",
|
|
|
|
"/yourpath/1.cpx",
|
|
|
|
"/yourpath/1.dat",
|
|
|
|
"/yourpath/1.idx")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("makeupDiff err is %v", err)
|
|
|
|
} else {
|
|
|
|
t.Log("makeupDiff Succeeded")
|
|
|
|
}
|
|
|
|
*/
|
2016-10-07 08:22:24 +00:00
|
|
|
}
|
2018-06-23 23:48:19 +00:00
|
|
|
|
2022-08-24 06:53:35 +00:00
|
|
|
func TestMemIndexCompaction(t *testing.T) {
|
|
|
|
testCompaction(t, NeedleMapInMemory)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLDBIndexCompaction(t *testing.T) {
|
|
|
|
testCompaction(t, NeedleMapLevelDb)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCompaction(t *testing.T, needleMapKind NeedleMapKind) {
|
2022-02-14 02:38:13 +00:00
|
|
|
dir := t.TempDir()
|
2018-06-23 23:48:19 +00:00
|
|
|
|
2022-08-24 06:53:35 +00:00
|
|
|
v, err := NewVolume(dir, dir, "", 1, needleMapKind, &super_block.ReplicaPlacement{}, &needle.TTL{}, 0, 0)
|
2018-06-23 23:48:19 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("volume creation: %v", err)
|
|
|
|
}
|
|
|
|
|
2019-05-04 00:22:39 +00:00
|
|
|
beforeCommitFileCount := 10000
|
|
|
|
afterCommitFileCount := 10000
|
2018-06-23 23:48:19 +00:00
|
|
|
|
2018-06-24 01:24:59 +00:00
|
|
|
infos := make([]*needleInfo, beforeCommitFileCount+afterCommitFileCount)
|
2018-06-23 23:48:19 +00:00
|
|
|
|
2018-06-24 01:24:59 +00:00
|
|
|
for i := 1; i <= beforeCommitFileCount; i++ {
|
|
|
|
doSomeWritesDeletes(i, v, t, infos)
|
2018-06-23 23:48:19 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 00:22:39 +00:00
|
|
|
startTime := time.Now()
|
2021-10-24 08:55:34 +00:00
|
|
|
v.Compact2(0, 0, nil)
|
2019-05-04 00:22:39 +00:00
|
|
|
speed := float64(v.ContentSize()) / time.Now().Sub(startTime).Seconds()
|
|
|
|
t.Logf("compaction speed: %.2f bytes/s", speed)
|
2018-06-24 01:24:59 +00:00
|
|
|
|
2022-08-24 06:53:35 +00:00
|
|
|
// update & delete original objects, upload & delete new objects
|
|
|
|
for i := 1; i <= afterCommitFileCount+beforeCommitFileCount; i++ {
|
|
|
|
doSomeWritesDeletes(i, v, t, infos)
|
2018-06-24 01:24:59 +00:00
|
|
|
}
|
2019-03-25 16:16:12 +00:00
|
|
|
v.CommitCompact()
|
2022-08-24 06:53:35 +00:00
|
|
|
realRecordCount := v.nm.IndexFileSize() / types.NeedleMapEntrySize
|
|
|
|
if needleMapKind == NeedleMapLevelDb {
|
|
|
|
nm := reflect.ValueOf(v.nm).Interface().(*LevelDbNeedleMap)
|
|
|
|
mm := nm.mapMetric
|
|
|
|
watermark := getWatermark(nm.db)
|
|
|
|
realWatermark := (nm.recordCount / watermarkBatchSize) * watermarkBatchSize
|
|
|
|
t.Logf("watermark from levelDB: %d, realWatermark: %d, nm.recordCount: %d, realRecordCount:%d, fileCount=%d, deletedcount:%d", watermark, realWatermark, nm.recordCount, realRecordCount, mm.FileCount(), v.DeletedCount())
|
|
|
|
if realWatermark != watermark {
|
|
|
|
t.Fatalf("testing watermark failed")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Logf("realRecordCount:%d, v.FileCount():%d mm.DeletedCount():%d", realRecordCount, v.FileCount(), v.DeletedCount())
|
|
|
|
}
|
|
|
|
if realRecordCount != v.FileCount() {
|
|
|
|
t.Fatalf("testing file count failed")
|
|
|
|
}
|
2018-06-23 23:48:19 +00:00
|
|
|
|
|
|
|
v.Close()
|
|
|
|
|
2022-08-24 06:53:35 +00:00
|
|
|
v, err = NewVolume(dir, dir, "", 1, needleMapKind, nil, nil, 0, 0)
|
2018-06-23 23:48:19 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("volume reloading: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-06-24 01:24:59 +00:00
|
|
|
for i := 1; i <= beforeCommitFileCount+afterCommitFileCount; i++ {
|
|
|
|
|
|
|
|
if infos[i-1] == nil {
|
|
|
|
t.Fatal("not found file", i)
|
|
|
|
}
|
2018-06-23 23:48:19 +00:00
|
|
|
|
|
|
|
if infos[i-1].size == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
n := newEmptyNeedle(uint64(i))
|
2021-08-09 06:25:16 +00:00
|
|
|
size, err := v.readNeedle(n, nil, nil)
|
2018-06-23 23:48:19 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("read file %d: %v", i, err)
|
|
|
|
}
|
2020-08-19 00:04:28 +00:00
|
|
|
if infos[i-1].size != types.Size(size) {
|
2018-06-23 23:48:19 +00:00
|
|
|
t.Fatalf("read file %d size mismatch expected %d found %d", i, infos[i-1].size, size)
|
|
|
|
}
|
|
|
|
if infos[i-1].crc != n.Checksum {
|
|
|
|
t.Fatalf("read file %d checksum mismatch expected %d found %d", i, infos[i-1].crc, n.Checksum)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-06-24 01:24:59 +00:00
|
|
|
func doSomeWritesDeletes(i int, v *Volume, t *testing.T, infos []*needleInfo) {
|
|
|
|
n := newRandomNeedle(uint64(i))
|
2021-08-13 09:09:35 +00:00
|
|
|
_, size, _, err := v.writeNeedle2(n, true, false)
|
2018-06-24 01:24:59 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("write file %d: %v", i, err)
|
|
|
|
}
|
|
|
|
infos[i-1] = &needleInfo{
|
|
|
|
size: size,
|
|
|
|
crc: n.Checksum,
|
|
|
|
}
|
2018-07-07 07:48:58 +00:00
|
|
|
// println("written file", i, "checksum", n.Checksum.Value(), "size", size)
|
2018-12-22 19:05:29 +00:00
|
|
|
if rand.Float64() < 0.03 {
|
2018-06-24 01:24:59 +00:00
|
|
|
toBeDeleted := rand.Intn(i) + 1
|
|
|
|
oldNeedle := newEmptyNeedle(uint64(toBeDeleted))
|
2020-05-07 11:58:06 +00:00
|
|
|
v.deleteNeedle2(oldNeedle)
|
2018-07-07 07:48:58 +00:00
|
|
|
// println("deleted file", toBeDeleted)
|
2018-06-24 01:24:59 +00:00
|
|
|
infos[toBeDeleted-1] = &needleInfo{
|
|
|
|
size: 0,
|
|
|
|
crc: n.Checksum,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-23 23:48:19 +00:00
|
|
|
|
|
|
|
type needleInfo struct {
|
2020-08-19 00:04:28 +00:00
|
|
|
size types.Size
|
2019-04-19 04:43:36 +00:00
|
|
|
crc needle.CRC
|
2018-06-23 23:48:19 +00:00
|
|
|
}
|
|
|
|
|
2019-04-19 04:43:36 +00:00
|
|
|
func newRandomNeedle(id uint64) *needle.Needle {
|
|
|
|
n := new(needle.Needle)
|
2018-06-23 23:48:19 +00:00
|
|
|
n.Data = make([]byte, rand.Intn(1024))
|
|
|
|
rand.Read(n.Data)
|
|
|
|
|
2019-04-19 04:43:36 +00:00
|
|
|
n.Checksum = needle.NewCRC(n.Data)
|
2018-07-08 09:39:04 +00:00
|
|
|
n.Id = types.Uint64ToNeedleId(id)
|
2018-06-23 23:48:19 +00:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
2019-04-19 04:43:36 +00:00
|
|
|
func newEmptyNeedle(id uint64) *needle.Needle {
|
|
|
|
n := new(needle.Needle)
|
2018-07-08 09:39:04 +00:00
|
|
|
n.Id = types.Uint64ToNeedleId(id)
|
2018-06-23 23:48:19 +00:00
|
|
|
return n
|
|
|
|
}
|