Ivan386/filestore fix (#7474)
* ipfs filestore fix [<obj>]... - Verify objects in filestore and remove bad links * Option --remove-bad-blocks for 'ipfs filestore verify' * fix call to DeleteBlock * action of --remove-bad-blocks in output only when option specified * Add sharness test for removing bad blocks --------- Co-authored-by: Andrew Gillis <11790789+gammazero@users.noreply.github.com>
Ivan committed
Jun 5, 2025 at 00:04 UTC
d39cb7f57554e2a41506b6022fa27dd58cb6215d
3 files changed
+90
-9
core/commands/filestore.go
+41
-8
@@ -27,7 +27,8 @@ var FileStoreCmd = &cmds.Command{
27
}
28
29
const (
30
- fileOrderOptionName = "file-order"
30
+ fileOrderOptionName = "file-order"
31
+ removeBadBlocksOptionName = "remove-bad-blocks"
32
)
33
34
var lsFileStore = &cmds.Command{
@@ -57,7 +58,7 @@ The output is:
58
}
59
args := req.Arguments
60
if len(args) > 0 {
60
- return listByArgs(req.Context, res, fs, args)
61
+ return listByArgs(req.Context, res, fs, args, false)
62
}
63
64
fileOrder, _ := req.Options[fileOrderOptionName].(bool)
@@ -108,7 +109,7 @@ otherwise verify all objects.
109
110
The output is:
111
111
-<status> <hash> <size> <path> <offset>
112
+<status> <hash> <size> <path> <offset> [<action>]
113
114
Where <status> is one of:
115
ok: the block can be reconstructed
@@ -118,6 +119,10 @@ error: there was some other problem reading the file
119
missing: <obj> could not be found in the filestore
120
ERROR: internal error, most likely due to a corrupt database
121
122
+Where <action> is present only when removing bad blocks and is one of:
123
+remove: link to the block will be removed from datastore
124
+keep: keep link, nothing to do
125
+
126
For ERROR entries the error will also be printed to stderr.
127
`,
128
},
@@ -126,15 +131,18 @@ For ERROR entries the error will also be printed to stderr.
131
},
132
Options: []cmds.Option{
133
cmds.BoolOption(fileOrderOptionName, "verify the objects based on the order of the backing file"),
134
+ cmds.BoolOption(removeBadBlocksOptionName, "remove bad blocks. WARNING: This may remove pinned data. You should run 'ipfs pin verify' after running this command and correct any issues."),
135
},
136
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
137
_, fs, err := getFilestore(env)
138
if err != nil {
139
return err
140
}
141
+
142
+ removeBadBlocks, _ := req.Options[removeBadBlocksOptionName].(bool)
143
args := req.Arguments
144
if len(args) > 0 {
137
- return listByArgs(req.Context, res, fs, args)
145
+ return listByArgs(req.Context, res, fs, args, removeBadBlocks)
146
}
147
148
fileOrder, _ := req.Options[fileOrderOptionName].(bool)
@@ -148,7 +156,14 @@ For ERROR entries the error will also be printed to stderr.
156
if r == nil {
157
break
158
}
151
- if err := res.Emit(r); err != nil {
159
+
160
+ if removeBadBlocks && (r.Status != filestore.StatusOk) && (r.Status != filestore.StatusOtherError) {
161
+ if err = fs.FileManager().DeleteBlock(req.Context, r.Key); err != nil {
162
+ return err
163
+ }
164
+ }
165
+
166
+ if err = res.Emit(r); err != nil {
167
return err
168
}
169
}
@@ -162,6 +177,8 @@ For ERROR entries the error will also be printed to stderr.
177
return err
178
}
179
180
+ req := res.Request()
181
+ removeBadBlocks, _ := req.Options[removeBadBlocksOptionName].(bool)
182
for {
183
v, err := res.Next()
184
if err != nil {
@@ -179,7 +196,16 @@ For ERROR entries the error will also be printed to stderr.
196
if list.Status == filestore.StatusOtherError {
197
fmt.Fprintf(os.Stderr, "%s\n", list.ErrorMsg)
198
}
182
- fmt.Fprintf(os.Stdout, "%s %s\n", list.Status.Format(), list.FormatLong(enc.Encode))
199
+
200
+ if removeBadBlocks {
201
+ action := "keep"
202
+ if removeBadBlocks && (list.Status != filestore.StatusOk) && (list.Status != filestore.StatusOtherError) {
203
+ action = "remove"
204
+ }
205
+ fmt.Fprintf(os.Stdout, "%s %s %s\n", list.Status.Format(), list.FormatLong(enc.Encode), action)
206
+ } else {
207
+ fmt.Fprintf(os.Stdout, "%s %s\n", list.Status.Format(), list.FormatLong(enc.Encode))
208
+ }
209
}
210
},
211
},
@@ -236,7 +262,7 @@ func getFilestore(env cmds.Environment) (*core.IpfsNode, *filestore.Filestore, e
262
return n, fs, err
263
}
264
239
-func listByArgs(ctx context.Context, res cmds.ResponseEmitter, fs *filestore.Filestore, args []string) error {
265
+func listByArgs(ctx context.Context, res cmds.ResponseEmitter, fs *filestore.Filestore, args []string, removeBadBlocks bool) error {
266
for _, arg := range args {
267
c, err := cid.Decode(arg)
268
if err != nil {
@@ -250,7 +276,14 @@ func listByArgs(ctx context.Context, res cmds.ResponseEmitter, fs *filestore.Fil
276
continue
277
}
278
r := filestore.Verify(ctx, fs, c)
253
- if err := res.Emit(r); err != nil {
279
+
280
+ if removeBadBlocks && (r.Status != filestore.StatusOk) && (r.Status != filestore.StatusOtherError) {
281
+ if err = fs.FileManager().DeleteBlock(ctx, r.Key); err != nil {
282
+ return err
283
+ }
284
+ }
285
+
286
+ if err = res.Emit(r); err != nil {
287
return err
288
}
289
}
docs/changelogs/v0.36.md
+6
-1
@@ -10,7 +10,8 @@ This release was brought to you by the [Shipyard](http://ipshipyard.com/) team.
10
11
- [Overview](#overview)
12
- [🔦 Highlights](#-highlights)
13
- - [Update go-log to v2](#update-go-log-to-v2)
13
+ - [Update go-log to v2](#update-go-log-to-v2
14
+ - [Option for filestore command to remove bad blocks](#option-for-filestore-command-to-remove-bad-blocks)
15
- [📦️ Important dependency updates](#-important-dependency-updates)
16
- [📝 Changelog](#-changelog)
17
- [👨👩👧👦 Contributors](#-contributors)
@@ -28,6 +29,10 @@ go-log v2 has been out for quite a while now and it is time to deprecate v1.
29
- Fixes `ipfs log tail`
30
- Removes support for `ContextWithLoggable` as this is not needed for tracing-like functionality
31
32
+#### Option for filestore command to remove bad blocks
33
+
34
+The `filestore` command has a new option, `--remove-bad-blocks`, to verify objects in the filestore and remove those that fail verification.
35
+
36
#### 📦️ Important dependency updates
37
38
- update `go-libp2p-kad-dht` to [v0.33.0](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.33.0)
test/sharness/t0271-filestore-utils.sh
+43
@@ -63,6 +63,20 @@ EOF
63
64
sort < verify_expect_file_order > verify_expect_key_order
65
66
+cat <<EOF > verify_rm_expect
67
+ok bafkreic2wqrsyr3y3qgzbvufen2w25r3p3zljckqyxkpcagsxz3zdcosd4 10000 somedir/file2 0 keep
68
+ok bafkreidx7ivgllulfkzyoo4oa7dfrg4mjmudg2qgdivoooj4s7lh3m5nqu 1000 somedir/file1 0 keep
69
+changed bafkreiemzfmzws23c2po4m6deiueknqfty7r3voes3e3zujmobrooc2ngm 262144 somedir/file3 0 remove
70
+changed bafkreifjcthslybjizk36xffcsb32fsbguxz3ptkl7723wz4u3qikttmam 213568 somedir/file3 786432 remove
71
+changed bafkreigl2pjptgxz6cexcnua56zc5dwsyrc4ph2eulmcb634oes6gzvmuy 262144 somedir/file3 524288 remove
72
+changed bafkreihgm53yhxn427lnfdwhqgpawc62qejog7gega5kqb6uwbyhjm47hu 262144 somedir/file3 262144 remove
73
+EOF
74
+
75
+cat <<EOF > verify_after_rm_expect
76
+ok bafkreic2wqrsyr3y3qgzbvufen2w25r3p3zljckqyxkpcagsxz3zdcosd4 10000 somedir/file2 0
77
+ok bafkreidx7ivgllulfkzyoo4oa7dfrg4mjmudg2qgdivoooj4s7lh3m5nqu 1000 somedir/file1 0
78
+EOF
79
+
80
IPFS_CMD="ipfs"
81
82
test_filestore_adds() {
@@ -155,6 +169,27 @@ test_filestore_verify() {
169
test_init_dataset
170
}
171
172
+test_filestore_rm_bad_blocks() {
173
+ test_filestore_state
174
+
175
+ test_expect_success "change first bit of file" '
176
+ dd if=/dev/zero of=somedir/file3 bs=1024 count=1
177
+ '
178
+
179
+ test_expect_success "'$IPFS_CMD filestore verify --remove-bad-blocks' shows changed file removed" '
180
+ $IPFS_CMD filestore verify --remove-bad-blocks > verify_rm_actual &&
181
+ test_cmp verify_rm_expect verify_rm_actual
182
+ '
183
+
184
+ test_expect_success "'$IPFS_CMD filestore verify' shows only files that were not removed" '
185
+ $IPFS_CMD filestore verify > verify_after &&
186
+ test_cmp verify_after_rm_expect verify_after
187
+ '
188
+
189
+ # reset the state for the next test
190
+ test_init_dataset
191
+}
192
+
193
test_filestore_dups() {
194
# make sure the filestore is in a clean state
195
test_filestore_state
@@ -179,6 +214,8 @@ test_filestore_verify
214
215
test_filestore_dups
216
217
+test_filestore_rm_bad_blocks
218
+
219
#
220
# With daemon
221
#
@@ -197,6 +234,8 @@ test_filestore_dups
234
235
test_kill_ipfs_daemon
236
237
+test_filestore_rm_bad_blocks
238
+
239
##
240
## base32
241
##
@@ -243,6 +282,8 @@ test_filestore_verify
282
283
test_filestore_dups
284
285
+test_filestore_rm_bad_blocks
286
+
287
#
288
# With daemon
289
#
@@ -263,6 +304,8 @@ test_kill_ipfs_daemon
304
305
test_done
306
307
+test_filestore_rm_bad_blocks
308
+
309
##
310
311
test_done