Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/control/cmd/ddb/commands_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,22 @@ func (ctx *DdbContext) CsumDump(path string, dst string, epoch uint64) error {
/* Run the c code command */
return daosError(ddb_run_csum_dump(&ctx.ctx, &options))
}

// CsumCheck recomputes the checksum(s) of the currently stored data at the VOS tree path and
// compares them against the checksum(s) already stored on disk, reporting a match/corruption
// verdict. It is read-only: no data or checksums are modified. epoch selects which version to
// check: for a single value akey it is the epoch at or before which the value is fetched, and
// for an array akey it is the maximal epoch of the visible record extent(s) to select. Pass
// math.MaxUint64 (EPOCH_MAX) to check the latest. By default, only corrupted entries are
// printed (plus a final summary); pass verbose to print every entry (matching, corrupted, and
// "no checksum").
func (ctx *DdbContext) CsumCheck(path string, epoch uint64, verbose bool) error {
/* Set up the options */
options := C.struct_csum_check_options{}
options.path = C.CString(path)
defer freeString(options.path)
options.epoch = C.uint64_t(epoch)
options.verbose = C.bool(verbose)
/* Run the c code command */
return daosError(ddb_run_csum_check(&ctx.ctx, &options))
}
30 changes: 30 additions & 0 deletions src/control/cmd/ddb/ddb_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,34 @@ select`,
},
Completer: nil,
})
// Command csum_check
app.AddCommand(&grumble.Command{
Name: "csum_check",
Aliases: nil,
Help: "Check visible checksum(s) against the stored data",
LongHelp: `Recompute the visible checksum(s) at the vos path from the currently
stored data and compare them against the checksum(s) already stored on disk. The vos
path should be a complete path, including the akey and if the value is an array
value it should include the extent. This command is read-only: no data or
checksums are modified. The --epoch flag selects which version of the checksum
to check: for a single value akey it selects the value visible at or before
that epoch, and for an array value it defines the maximal epoch of the visible
record extent to select. By default, nothing is printed unless corruption is
detected: only corrupted entries are printed, followed by a final error
summary; a clean result (matching or no checksum stored) produces no output
at all. Pass --verbose to print every entry regardless of outcome (matching,
no checksum stored, or corrupted), plus a final summary line even on success`,
HelpGroup: "vos",
Args: func(a *grumble.Args) {
a.String("path", "VOS tree path to check.")
},
Flags: func(f *grumble.Flags) {
f.Uint64("e", "epoch", math.MaxUint64, "Maximal epoch of the checksum value to select (default EPOCH_MAX).")
f.Bool("v", "verbose", false, "Print every checksum entry, not just corrupted ones.")
},
Run: func(c *grumble.Context) error {
return ctx.CsumCheck(c.Args.String("path"), c.Flags.Uint64("epoch"), c.Flags.Bool("verbose"))
},
Completer: nil,
})
}
66 changes: 66 additions & 0 deletions src/control/cmd/ddb/ddb_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ func TestDdb_HelpCmds(t *testing.T) {
cmdStr: "csum_dump",
helpSubStr: "Usage:\n csum_dump [flags] path [dst]\n",
},
"help for 'csum_check' command": {
cmdStr: "csum_check",
helpSubStr: "Usage:\n csum_check [flags] path\n",
},
} {
t.Run(name, func(t *testing.T) {
ctx := newTestContext(t)
Expand Down Expand Up @@ -277,6 +281,16 @@ func TestDdb_Cmds(t *testing.T) {
}
}

csumCheckFnChecking := func(t *testing.T, wantPath string, wantEpoch uint64, wantVerbose bool) func(string, uint64, bool) error {
return func(path string, epoch uint64, verbose bool) error {
fmt.Println("csum_check called")
test.CmpAny(t, "path", wantPath, path)
test.CmpAny(t, "epoch", wantEpoch, epoch)
test.CmpAny(t, "verbose", wantVerbose, verbose)
return nil
}
}

for name, tc := range map[string]struct {
args []string
setup func(*testing.T)
Expand Down Expand Up @@ -854,6 +868,58 @@ func TestDdb_Cmds(t *testing.T) {
},
expStdout: []string{"csum_dump called"},
},

// --- csum_check command ---
"csum_check missing path": {
args: []string{"csum_check"},
expErr: ddbTestErr("missing argument 'path'"),
},
"csum_check invalid options": {
args: []string{"csum_check", "--bar"},
expErr: ddbTestErr("invalid flag: --bar"),
},
"csum_check default": {
args: []string{"csum_check", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", math.MaxUint64, false)
},
expStdout: []string{"csum_check called"},
},
"csum_check epoch short": {
args: []string{"csum_check", "-e", "999", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", 999, false)
},
expStdout: []string{"csum_check called"},
},
"csum_check epoch long": {
args: []string{"csum_check", "--epoch=666", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", 666, false)
},
expStdout: []string{"csum_check called"},
},
"csum_check verbose short": {
args: []string{"csum_check", "-v", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", math.MaxUint64, true)
},
expStdout: []string{"csum_check called"},
},
"csum_check verbose long": {
args: []string{"csum_check", "--verbose", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", math.MaxUint64, true)
},
expStdout: []string{"csum_check called"},
},
"csum_check verbose and epoch": {
args: []string{"csum_check", "-e", "999", "-v", "/[0]"},
setup: func(t *testing.T) {
ddb_run_csum_check_Fn = csumCheckFnChecking(t, "/[0]", 999, true)
},
expStdout: []string{"csum_check called"},
},
} {
t.Run(name, func(t *testing.T) {
checkCmd := func(t *testing.T, stdout string, err error) {
Expand Down
4 changes: 4 additions & 0 deletions src/control/cmd/ddb/libddb.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,7 @@ func ddb_run_dtx_aggr(ctx *C.struct_ddb_ctx, opts *C.struct_dtx_aggr_options) C.
func ddb_run_csum_dump(ctx *C.struct_ddb_ctx, opts *C.struct_csum_dump_options) C.int {
return C.ddb_run_csum_dump(ctx, opts)
}

func ddb_run_csum_check(ctx *C.struct_ddb_ctx, opts *C.struct_csum_check_options) C.int {
return C.ddb_run_csum_check(ctx, opts)
}
17 changes: 17 additions & 0 deletions src/control/cmd/ddb/libddb_stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func resetDdbStubs() {
ddb_run_prov_mem_RC, ddb_run_prov_mem_Fn = 0, nil
ddb_run_dtx_aggr_RC, ddb_run_dtx_aggr_Fn = 0, nil
ddb_run_csum_dump_RC, ddb_run_csum_dump_Fn = 0, nil
ddb_run_csum_check_RC, ddb_run_csum_check_Fn = 0, nil
}

var ddb_init_RC C.int = 0
Expand Down Expand Up @@ -475,3 +476,19 @@ func ddb_run_csum_dump(_ *C.struct_ddb_ctx, opts *C.struct_csum_dump_options) C.
}
return ddb_run_csum_dump_RC
}

var (
ddb_run_csum_check_RC C.int = 0
ddb_run_csum_check_Fn func(path string, epoch uint64, verbose bool) error
)

func ddb_run_csum_check(_ *C.struct_ddb_ctx, opts *C.struct_csum_check_options) C.int {
if ddb_run_csum_check_Fn != nil {
return fromGoErr(ddb_run_csum_check_Fn(
C.GoString(opts.path),
uint64(opts.epoch),
bool(opts.verbose),
))
}
return ddb_run_csum_check_RC
}
2 changes: 2 additions & 0 deletions src/utils/ddb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ smd

vos
close Close the currently opened vos pool shard
csum_check Check visible checksum(s) against the stored data
csum_dump Dump visible checksum(s)
dev_list List all devices
dev_replace Replace an old device with a new unused device
dtx_act_abort Mark the active dtx entry as aborted
Expand Down
Loading