-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelper.go
144 lines (118 loc) · 3.2 KB
/
helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package diskv
import (
"context"
"fmt"
"os"
)
// 迁移 idx 文件
func (d *Diskv) MigrateIdx(ctx context.Context, toConfig *CreateConfig) error {
d.mu.Lock()
defer d.mu.Unlock()
toConfig.Dir = d.dir
toIdxFile := d.idxFileName(d.dir) + ".tmp"
toIdx, err := d.createIdx(ctx, toIdxFile, *toConfig)
if err != nil {
return fmt.Errorf("create idx file error: %s", err)
}
ferr := d.forEachKey(ctx, func(ctx context.Context, valMeta *valueMeta) (ok bool) {
err = toIdx.setValueMeta(ctx, valMeta)
if err != nil {
return false
}
return true
})
if ferr != nil {
return fmt.Errorf("forEachKey error: %s", ferr)
}
if err != nil {
return fmt.Errorf("forEachKey error in func: %s", err)
}
err = migrateFile(ctx, toIdxFile, d.idxFile, false)
if err != nil {
return fmt.Errorf("migrate file error: %s", err)
}
err = d.openDB(ctx, d.dir)
if err != nil {
return fmt.Errorf("reopen db file error: %s", err)
}
return nil
}
// 迁移 value 文件,用于把 del 等操作去除掉
func (d *Diskv) MigrateValue(ctx context.Context) error {
d.mu.Lock()
defer d.mu.Unlock()
toValueFile := d.dbFileName(d.dir) + ".tmp"
dbstore, err := d.getOrCreateDBStore(toValueFile)
if err != nil {
return fmt.Errorf("create db file error: %s", err)
}
idxMeta, err := d.idx.getIdxMeta(ctx)
if err != nil {
return fmt.Errorf("get idx meta error: %s", err)
}
toValueIdxFile := d.idxFileName(d.dir) + ".tmp"
nidx, err := d.createIdx(ctx, toValueIdxFile, CreateConfig{
Dir: d.dir,
// KeySize: idxMeta.keySize,
KeysLen: idxMeta.keysLen,
// OffsetSize: idxMeta.offsetSize,
// ValueLenSize: idxMeta.valueLenSize,
MaxLen: idxMeta.maxLength,
})
if err != nil {
return fmt.Errorf("create idx file error: %s", err)
}
ferr := d.forEach(ctx, func(ctx context.Context, key string, value []byte) (ok bool) {
var valueMeta *valueMeta
valueMeta, err = dbstore.write(ctx, &valueItem{key: key, value: value})
if err != nil {
return false
}
err = nidx.setValueMeta(ctx, valueMeta)
if err != nil {
return false
}
return true
})
if ferr != nil {
return fmt.Errorf("forEachKey error: %s", ferr)
}
if err != nil {
return fmt.Errorf("forEachKey error in func: %s", err)
}
err = migrateFile(ctx, toValueFile, d.dbFile, false)
if err != nil {
return fmt.Errorf("migrate file error: %s", err)
}
err = migrateFile(ctx, toValueIdxFile, d.idxFile, false)
if err != nil {
return fmt.Errorf("migrate file error: %s", err)
}
err = d.openDB(ctx, d.dir)
if err != nil {
return fmt.Errorf("reopen db file error: %s", err)
}
return nil
}
func migrateFile(ctx context.Context, from string, to string, removeBak bool) error {
toBackFile := to + "._bak"
err := os.RemoveAll(toBackFile)
if err != nil {
return fmt.Errorf("remove old bak file [%s] error: %s", toBackFile, err)
}
err = os.Rename(to, toBackFile)
if err != nil {
return fmt.Errorf("rename old file [%s => %s] error: %s", to, toBackFile, err)
}
err = os.Rename(from, to)
if err != nil {
return fmt.Errorf("rename new file [%s => %s] error: %s", from, to, err)
}
if removeBak {
err = os.RemoveAll(toBackFile)
if err != nil {
return fmt.Errorf("remove old bak file [%s] error: %s", toBackFile, err)
}
}
return nil
}