Skip to content

Commit

Permalink
superfluous response; non-existence; CLI ec-encode v2
Browse files Browse the repository at this point in the history
* fix "superfluous response" from HEAD(bucket) when given invalid URL
* fix fs/walk vs concurrent object deletion
  - non-existence (condition) includes missing-metadata
* CLI: revise/rewrite 'ais start ec-encode' and 'ais start mirror'
* with refactoring and renaming

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Sep 6, 2024
1 parent b108c42 commit 7139207
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 163 deletions.
8 changes: 6 additions & 2 deletions ais/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -1862,8 +1862,12 @@ func (p *proxy) httpbckhead(w http.ResponseWriter, r *http.Request, apireq *apiR
var prefix string

// preparse
if items, err := p.parseURL(w, r, apireq.prefix, apireq.after, true); err == nil {
debug.Assert(apireq.bckIdx == 0, "expecting bucket name at idx = 0")
{
items, err := p.parseURL(w, r, apireq.prefix, apireq.after, true)
if err != nil {
return
}
debug.Assert(apireq.bckIdx == 0, "expecting bucket name at index 0 (zero)")
if len(items) > 1 {
prefix = items[1]
for _, s := range items[2:] {
Expand Down
166 changes: 166 additions & 0 deletions cmd/cli/cli/bencodeway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Package cli provides easy-to-use commands to manage, monitor, and utilize AIS clusters.
// This file handles specific bucket actions.
/*
* Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*/
package cli

import (
"fmt"

"github.com/NVIDIA/aistore/api"
"github.com/NVIDIA/aistore/cmn"
"github.com/urfave/cli"
)

var (
storageSvcCmdsFlags = map[string][]cli.Flag{
commandMirror: {
copiesFlag,
nonverboseFlag,
},
commandECEncode: {
dataSlicesFlag,
paritySlicesFlag,
nonverboseFlag,
},
}

storageSvcCmds = []cli.Command{
{
Name: commandMirror,
Usage: "configure (or unconfigure) bucket as n-way mirror, and run the corresponding batch job, e.g.:\n" +
indent1 + "\t- 'ais start mirror ais://m --copies 3'\t- configure ais://m as a 3-way mirror;\n" +
indent1 + "\t- 'ais start mirror ais://m --copies 1'\t- configure ais://m for no redundancy (no extra copies).\n" +
indent1 + "(see also: 'ais start ec-encode')",
ArgsUsage: bucketArgument,
Flags: storageSvcCmdsFlags[commandMirror],
Action: setCopiesHandler,
BashComplete: bucketCompletions(bcmplop{}),
},
{
Name: commandECEncode,
Usage: "erasure code entire bucket, e.g.:\n" +
indent1 + "\t- 'ais start ec-encode ais://m -d 8 -p 2'\t- erasure-code ais://m for (D=8, P=2).\n" +
indent1 + "(see also: 'ais start mirror')",
ArgsUsage: bucketArgument,
Flags: storageSvcCmdsFlags[commandECEncode],
Action: ecEncodeHandler,
BashComplete: bucketCompletions(bcmplop{}),
},
}
)

func setCopiesHandler(c *cli.Context) (err error) {
var (
bck cmn.Bck
p *cmn.Bprops
)
if bck, err = parseBckURI(c, c.Args().Get(0), false); err != nil {
return
}
if p, err = headBucket(bck, false /* don't add */); err != nil {
return
}

copies := c.Int(copiesFlag.Name)
if p.Mirror.Copies == int64(copies) {
if copies > 1 && p.Mirror.Enabled {
fmt.Fprintf(c.App.Writer, "%s is already %d-way mirror, nothing to do\n", bck.Cname(""), copies)
return
}
if copies < 2 {
fmt.Fprintf(c.App.Writer, "%s is already configured with no redundancy, nothing to do\n", bck.Cname(""))
return
}
}
return nway(c, bck, copies)
}

func nway(c *cli.Context, bck cmn.Bck, copies int) (err error) {
var xid string
if xid, err = api.MakeNCopies(apiBP, bck, copies); err != nil {
return
}
if flagIsSet(c, nonverboseFlag) {
fmt.Fprintln(c.App.Writer, xid)
return nil
}
var baseMsg string
if copies > 1 {
baseMsg = fmt.Sprintf("Configured %s as %d-way mirror. ", bck.Cname(""), copies)
} else {
baseMsg = fmt.Sprintf("Configured %s for single-replica (no redundancy). ", bck.Cname(""))
}
actionDone(c, baseMsg+toMonitorMsg(c, xid, ""))
return nil
}

func ecEncodeHandler(c *cli.Context) error {
bck, err := parseBckURI(c, c.Args().Get(0), false)
if err != nil {
return err
}

var (
bprops *cmn.Bprops
numd, nump int
warned bool
)
if bprops, err = headBucket(bck, false /* don't add */); err != nil {
return err
}
numd = c.Int(fl1n(dataSlicesFlag.Name))
nump = c.Int(fl1n(paritySlicesFlag.Name))

// compare with ECConf.Validate
if numd < cmn.MinSliceCount || numd > cmn.MaxSliceCount {
return fmt.Errorf("invalid number %d of data slices (valid range: [%d, %d])", numd, cmn.MinSliceCount, cmn.MaxSliceCount)
}
if nump < cmn.MinSliceCount || nump > cmn.MaxSliceCount {
return fmt.Errorf("invalid number %d of parity slices (valid range: [%d, %d])", nump, cmn.MinSliceCount, cmn.MaxSliceCount)
}

if bprops.EC.Enabled {
if bprops.EC.DataSlices != numd || bprops.EC.ParitySlices != nump {
// not supported yet:
warn := fmt.Sprintf("%s is already erasure-coded, cannot change existing (D=%d, P=%d) configuration to (D=%d, P=%d)",
bck.Cname(""), bprops.EC.DataSlices, bprops.EC.ParitySlices, numd, nump)
actionWarn(c, warn)
return nil
}
var warn string
if bprops.EC.ObjSizeLimit == cmn.ObjSizeToAlwaysReplicate {
warn = fmt.Sprintf("%s is already configured for (P + 1 = %d copies)", bck.Cname(""), bprops.EC.ParitySlices+1)
} else {
warn = fmt.Sprintf("%s is already erasure-coded for (D=%d, P=%d)", bck.Cname(""), numd, nump)
}
actionWarn(c, warn+" - proceeding to run anyway")
warned = true
}

return ecEncode(c, bck, bprops, numd, nump, warned)
}

func ecEncode(c *cli.Context, bck cmn.Bck, bprops *cmn.Bprops, data, parity int, warned bool) error {
xid, err := api.ECEncodeBucket(apiBP, bck, data, parity)
if err != nil {
return err
}
if flagIsSet(c, nonverboseFlag) {
fmt.Fprintln(c.App.Writer, xid)
return nil
}
if warned {
actionDone(c, toMonitorMsg(c, xid, ""))
} else {
var msg string
if bprops.EC.ObjSizeLimit == cmn.ObjSizeToAlwaysReplicate {
msg = fmt.Sprintf("Erasure-coding %s for (P + 1 = %d copies). ", bck.Cname(""), bprops.EC.ParitySlices+1)
} else {
msg = fmt.Sprintf("Erasure-coding %s for (D=%d, P=%d). ", bck.Cname(""), data, parity)
}
actionDone(c, msg+toMonitorMsg(c, xid, ""))
}
return nil
}
35 changes: 0 additions & 35 deletions cmd/cli/cli/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,38 +427,3 @@ func headBckTable(c *cli.Context, props, defProps *cmn.Bprops, section string) e
}
return teb.Print(propList, teb.PropValTmpl)
}

// Configure bucket as n-way mirror
func configureNCopies(c *cli.Context, bck cmn.Bck, copies int) (err error) {
var xid string
if xid, err = api.MakeNCopies(apiBP, bck, copies); err != nil {
return
}
if flagIsSet(c, nonverboseFlag) {
fmt.Fprintln(c.App.Writer, xid)
return nil
}
var baseMsg string
if copies > 1 {
baseMsg = fmt.Sprintf("Configured %s as %d-way mirror. ", bck.Cname(""), copies)
} else {
baseMsg = fmt.Sprintf("Configured %s for single-replica (no redundancy). ", bck.Cname(""))
}
actionDone(c, baseMsg+toMonitorMsg(c, xid, ""))
return nil
}

// erasure code the entire bucket
func ecEncode(c *cli.Context, bck cmn.Bck, data, parity int) (err error) {
var xid string
if xid, err = api.ECEncodeBucket(apiBP, bck, data, parity); err != nil {
return
}
if flagIsSet(c, nonverboseFlag) {
fmt.Fprintln(c.App.Writer, xid)
} else {
msg := fmt.Sprintf("Erasure-coding bucket %s. ", bck.Cname(""))
actionDone(c, msg+toMonitorMsg(c, xid, ""))
}
return nil
}
10 changes: 6 additions & 4 deletions cmd/cli/cli/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,12 +583,14 @@ var (
Usage: "bucket inventory ID (optional; by default, we use bucket name as the bucket's inventory ID)",
}

keepMDFlag = cli.BoolFlag{Name: "keep-md", Usage: "keep bucket metadata"}

copiesFlag = cli.IntFlag{Name: "copies", Usage: "number of object replicas", Value: 1, Required: true}

keepMDFlag = cli.BoolFlag{Name: "keep-md", Usage: "keep bucket metadata"}
dataSlicesFlag = cli.IntFlag{Name: "data-slices,data,d", Usage: "number of data slices", Required: true}
paritySlicesFlag = cli.IntFlag{Name: "parity-slices,parity,p", Usage: "number of parity slices", Required: true}
compactPropFlag = cli.BoolFlag{Name: "compact,c", Usage: "display properties grouped in human-readable mode"}
dataSlicesFlag = cli.IntFlag{Name: "data-slices,data,d", Value: 2, Usage: "number of data slices", Required: true}
paritySlicesFlag = cli.IntFlag{Name: "parity-slices,parity,p", Value: 2, Usage: "number of parity slices", Required: true}

compactPropFlag = cli.BoolFlag{Name: "compact,c", Usage: "display properties grouped in human-readable mode"}

nameOnlyFlag = cli.BoolFlag{
Name: "name-only",
Expand Down
96 changes: 0 additions & 96 deletions cmd/cli/cli/reliability_hdlr.go

This file was deleted.

6 changes: 3 additions & 3 deletions cmd/cli/cli/search_hdlr.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Package cli provides easy-to-use commands to manage, monitor, and utilize AIS clusters.
// This file provides commands that remove various entities from the cluster.
/*
* Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*/
package cli

Expand Down Expand Up @@ -33,8 +33,8 @@ var (
commandCopy: {"copy", "replicate", "backup"},
commandGet: {"fetch", "read", "download"},
commandPrefetch: {"load", "preload", "warmup", "cache", "get"},
commandMirror: {"protect", "replicate", "copy"},
commandECEncode: {"protect", "encode", "replicate", "erasure-code"},
commandMirror: {"protect", "replicate", "copy", "n-way", "backup", "redundancy"},
commandECEncode: {"protect", "encode", "replicate", "erasure-code", "backup", "redundancy"},
commandStart: {"do", "run", "execute"},
commandStop: {"abort", "terminate"},
commandPut: {"update", "write", "promote", "modify", "upload"},
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/NVIDIA/aistore/cmd/cli
go 1.22.3

require (
github.com/NVIDIA/aistore v1.3.24-0.20240903143228-530288d44fa5
github.com/NVIDIA/aistore v1.3.24-0.20240906164715-2998ad1bbf9f
github.com/fatih/color v1.17.0
github.com/json-iterator/go v1.1.12
github.com/onsi/ginkgo/v2 v2.20.0
Expand Down
4 changes: 2 additions & 2 deletions cmd/cli/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/NVIDIA/aistore v1.3.24-0.20240903143228-530288d44fa5 h1:VXxr9tH0VU81wzlmVSWY3LyuyK43kflrNp6MDo6rTN8=
github.com/NVIDIA/aistore v1.3.24-0.20240903143228-530288d44fa5/go.mod h1:si83S9r29vwIC0f0CE2Mk+25bFiaN6mmVlmuBpP4hHM=
github.com/NVIDIA/aistore v1.3.24-0.20240906164715-2998ad1bbf9f h1:Prd6cKrvxO/QaU4q+c2LWhk6bSUAoLZ4aAXQoIdv8L8=
github.com/NVIDIA/aistore v1.3.24-0.20240906164715-2998ad1bbf9f/go.mod h1:si83S9r29vwIC0f0CE2Mk+25bFiaN6mmVlmuBpP4hHM=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
Expand Down
Loading

0 comments on commit 7139207

Please sign in to comment.