Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support querying status for multiple CIDs in clients #1592

Merged
merged 2 commits into from
Mar 1, 2022
Merged
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
2 changes: 2 additions & 0 deletions api/rest/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ type Client interface {
// the information affects only the current peer, otherwise the information
// is fetched from all cluster peers.
Status(ctx context.Context, ci cid.Cid, local bool) (*api.GlobalPinInfo, error)
// StatusCids status information for the requested CIDs.
StatusCids(ctx context.Context, cids []cid.Cid, local bool) ([]*api.GlobalPinInfo, error)
// StatusAll gathers Status() for all tracked items.
StatusAll(ctx context.Context, filter api.TrackerStatus, local bool) ([]*api.GlobalPinInfo, error)

Expand Down
15 changes: 15 additions & 0 deletions api/rest/client/lbclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,21 @@ func (lc *loadBalancingClient) Status(ctx context.Context, ci cid.Cid, local boo
return pinInfo, err
}

// StatusCids returns Status() information for the given Cids. If local is
// true, the information affects only the current peer, otherwise the
// information is fetched from all cluster peers.
func (lc *loadBalancingClient) StatusCids(ctx context.Context, cids []cid.Cid, local bool) ([]*api.GlobalPinInfo, error) {
var pinInfos []*api.GlobalPinInfo
call := func(c Client) error {
var err error
pinInfos, err = c.StatusCids(ctx, cids, local)
return err
}

err := lc.retry(0, call)
return pinInfos, err
}

// StatusAll gathers Status() for all tracked items. If a filter is
// provided, only entries matching the given filter statuses
// will be returned. A filter can be built by merging TrackerStatuses with
Expand Down
19 changes: 18 additions & 1 deletion api/rest/client/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,23 @@ func (c *defaultClient) Status(ctx context.Context, ci cid.Cid, local bool) (*ap
return &gpi, err
}

// StatusCids returns Status() information for the given Cids. If local is
// true, the information affects only the current peer, otherwise the
// information is fetched from all cluster peers.
func (c *defaultClient) StatusCids(ctx context.Context, cids []cid.Cid, local bool) ([]*api.GlobalPinInfo, error) {
return c.statusAllWithCids(ctx, api.TrackerStatusUndefined, cids, local)
}

// StatusAll gathers Status() for all tracked items. If a filter is
// provided, only entries matching the given filter statuses
// will be returned. A filter can be built by merging TrackerStatuses with
// a bitwise OR operation (st1 | st2 | ...). A "0" filter value (or
// api.TrackerStatusUndefined), means all.
func (c *defaultClient) StatusAll(ctx context.Context, filter api.TrackerStatus, local bool) ([]*api.GlobalPinInfo, error) {
return c.statusAllWithCids(ctx, filter, nil, local)
}

func (c *defaultClient) statusAllWithCids(ctx context.Context, filter api.TrackerStatus, cids []cid.Cid, local bool) ([]*api.GlobalPinInfo, error) {
ctx, span := trace.StartSpan(ctx, "client/StatusAll")
defer span.End()

Expand All @@ -239,10 +250,16 @@ func (c *defaultClient) StatusAll(ctx context.Context, filter api.TrackerStatus,
}
}

cidsStr := make([]string, len(cids))
for i, c := range cids {
cidsStr[i] = c.String()
}

err := c.do(
ctx,
"GET",
fmt.Sprintf("/pins?local=%t&filter=%s", local, url.QueryEscape(filterStr)),
fmt.Sprintf("/pins?local=%t&filter=%s&cids=%s",
local, url.QueryEscape(filterStr), strings.Join(cidsStr, ",")),
nil,
nil,
&gpis,
Expand Down
21 changes: 21 additions & 0 deletions api/rest/client/methods_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,27 @@ func TestStatus(t *testing.T) {
testClients(t, api, testF)
}

func TestStatusCids(t *testing.T) {
ctx := context.Background()
api := testAPI(t)
defer shutdown(api)

testF := func(t *testing.T, c Client) {
pins, err := c.StatusCids(ctx, []cid.Cid{test.Cid1}, false)
if err != nil {
t.Fatal(err)
}
if len(pins) != 1 {
t.Fatal("wrong number of pins returned")
}
if !pins[0].Cid.Equals(test.Cid1) {
t.Error("should be same pin")
}
}

testClients(t, api, testF)
}

func TestStatusAll(t *testing.T) {
ctx := context.Background()
api := testAPI(t)
Expand Down
21 changes: 14 additions & 7 deletions cmd/ipfs-cluster-ctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -860,8 +860,8 @@ The filter only takes effect when listing all pins. The possible values are:
Description: `
This command retrieves the status of the CIDs tracked by IPFS
Cluster, including which member is pinning them and any errors.
If a CID is provided, the status will be only fetched for a single
item. Metadata CIDs are included in the status response
If one of several CIDs are provided, the status will be only fetched
for a single item. Metadata CIDs are included in the status response.

When the --local flag is passed, it will only fetch the status from the
contacted cluster peer. By default, status will be fetched from all peers.
Expand All @@ -871,7 +871,7 @@ where status of the pin matches at least one of the filter values (a comma
separated list). The following are valid status values:

` + trackerStatusAllString(),
ArgsUsage: "[CID]",
ArgsUsage: "[CID1] [CID2]...",
Flags: []cli.Flag{
localFlag(),
cli.StringFlag{
Expand All @@ -880,11 +880,18 @@ separated list). The following are valid status values:
},
},
Action: func(c *cli.Context) error {
cidStr := c.Args().First()
if cidStr != "" {
ci, err := cid.Decode(cidStr)
cidsStr := c.Args()
cids := make([]cid.Cid, len(cidsStr))
for i, cStr := range cidsStr {
ci, err := cid.Decode(cStr)
checkErr("parsing cid", err)
resp, cerr := globalClient.Status(ctx, ci, c.Bool("local"))
cids[i] = ci
}
if len(cids) == 1 {
resp, cerr := globalClient.Status(ctx, cids[0], c.Bool("local"))
formatResponse(c, resp, cerr)
} else if len(cids) > 1 {
resp, cerr := globalClient.StatusCids(ctx, cids, c.Bool("local"))
formatResponse(c, resp, cerr)
} else {
filterFlag := c.String("filter")
Expand Down