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

Forward warning for unoptimal index #3430

Merged
merged 1 commit into from
Jun 13, 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
18 changes: 18 additions & 0 deletions docs/couchdb-quirks.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ reasons. In general, you can follow these two rules of thumb:
omit the `sort` operator on the query (except if you want the `descending`
order).

### Warnings for slow requests

When requesting a mango index, CouchDB can use an index. But there are also
cases where no index can be used, or where the index is not optimal. Let's
see the different scenarios:

- CouchDB does use an index, it will respond with a warning, and cozy-stack
nono marked this conversation as resolved.
Show resolved Hide resolved
will transform this warning in an error, as developers should really avoid
this issue

- CouchDB can use an index for the selector but not for the sort, it will
respond with an error, and the cozy-stack will just forward the error

- CouchDB can use an index, but will still look at much more documents in
the index that what will be in the response (it happens with `$or` and `$in`
operators, which should be avoided), CouchDB 3+ will send a warning and the
cozy-stack will forward the documents and the warning to the client.

### Comparison of strings

Comparison of strings is done using ICU which implements the Unicode Collation
Expand Down
4 changes: 2 additions & 2 deletions pkg/couchdb/couchdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,8 +913,8 @@ func findDocsRaw(db prefixer.Prefixer, doctype string, req interface{}, results
}
return nil, err
}
if !ignoreUnoptimized && response.Warning != "" {
// Developer should not rely on unoptimized index.
if !ignoreUnoptimized && strings.Contains(response.Warning, "matching index found") {
// Developers should not rely on fullscan with no index.
return nil, unoptimalError()
}
if response.Bookmark == "nil" {
Expand Down
1 change: 1 addition & 0 deletions pkg/jsonapi/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Object interface {
// in JSON-API land
type Meta struct {
Rev string `json:"rev,omitempty"`
Warning string `json:"warning,omitempty"`
Count *int `json:"count,omitempty"`
ExecutionStats *couchdb.ExecutionStats `json:"execution_stats,omitempty"`
}
Expand Down
12 changes: 7 additions & 5 deletions pkg/jsonapi/jsonapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,14 @@ func Data(c echo.Context, statusCode int, o Object, links *LinksList) error {
// DataList can be called to send an multiple-value answer with a
// JSON-API document contains multiple objects.
func DataList(c echo.Context, statusCode int, objs []Object, links *LinksList) error {
return DataListWithTotal(c, statusCode, len(objs), objs, links, nil)
count := len(objs)
meta := Meta{Count: &count}
return DataListWithMeta(c, statusCode, meta, objs, links)
}

// DataListWithTotal can be called to send a list of Object with a different
// meta:count, useful to indicate total number of results with pagination.
func DataListWithTotal(c echo.Context, statusCode, total int, objs []Object, links *LinksList, executionStats *couchdb.ExecutionStats) error {
// DataListWithMeta can be called to send a list of Objects with meta like a
// count, useful to indicate total number of results with pagination.
func DataListWithMeta(c echo.Context, statusCode int, meta Meta, objs []Object, links *LinksList) error {
objsMarshaled := make([]json.RawMessage, len(objs))
for i, o := range objs {
j, err := MarshalObject(o)
Expand All @@ -95,7 +97,7 @@ func DataListWithTotal(c echo.Context, statusCode, total int, objs []Object, lin

doc := Document{
Data: (*json.RawMessage)(&data),
Meta: &Meta{Count: &total, ExecutionStats: executionStats},
Meta: &meta,
Links: links,
}

Expand Down
3 changes: 3 additions & 0 deletions web/data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ func findDocuments(c echo.Context) error {
if resp.ExecutionStats != nil {
out["execution_stats"] = resp.ExecutionStats
}
if resp.Warning != "" {
out["warning"] = resp.Warning
}
return c.JSON(http.StatusOK, out)
}

Expand Down
7 changes: 6 additions & 1 deletion web/files/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,12 @@ func FindFilesMango(c echo.Context) error {
}
}

return jsonapi.DataListWithTotal(c, http.StatusOK, total, out, &links, resp.ExecutionStats)
meta := jsonapi.Meta{
Count: &total,
ExecutionStats: resp.ExecutionStats,
Warning: resp.Warning,
}
return jsonapi.DataListWithMeta(c, http.StatusOK, meta, out, &links)
}

var allowedChangesParams = map[string]bool{
Expand Down
3 changes: 2 additions & 1 deletion web/files/paginated.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ func dirDataList(c echo.Context, statusCode int, doc *vfs.DirDoc) error {
links.Next = next
}

return jsonapi.DataListWithTotal(c, statusCode, count, included, &links, nil)
meta := jsonapi.Meta{Count: &count}
return jsonapi.DataListWithMeta(c, statusCode, meta, included, &links)
}

// NewFile creates an instance of file struct from a vfs.FileDoc document.
Expand Down