journal: fix reading omaps from objects with large key counts

The implementation of getOMapValues assumed that the number of key-value
pairs assigned to the object would be close to the number of keys
being requested. When the number of keys on the object exceeded the
"listExcess" value the function would fail to read additional keys
even if they existed in the omap.
This change sets a large fixed "chunk size" value and keeps reading
key-value pairs as long as the callback gets called and increments
the numKeys counter.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2020-11-05 10:47:57 -05:00 committed by mergify[bot]
parent 7caca1137f
commit 8a41cd03a5

View File

@ -25,9 +25,10 @@ import (
"github.com/ceph/go-ceph/rados"
)
// listExcess is the number of false-positive key-value pairs we will
// accept from ceph when getting omap values.
var listExcess = 32
// chunkSize is the number of key-value pairs that will be fetched in
// one call. This is set fairly large to avoid calling into ceph APIs
// over and over.
const chunkSize int64 = 512
func getOMapValues(
ctx context.Context,
@ -51,15 +52,26 @@ func getOMapValues(
for i := range keys {
want[keys[i]] = true
}
numKeys := uint64(0)
startAfter := ""
for {
prevNumKeys := numKeys
err = ioctx.ListOmapValues(
oid, startAfter, prefix, chunkSize,
func(key string, value []byte) {
numKeys++
startAfter = key
if want[key] {
results[key] = string(value)
}
},
)
// if we hit an error, or no new keys were seen, exit the loop
if err != nil || numKeys == prevNumKeys {
break
}
}
err = ioctx.ListOmapValues(
oid, "", prefix, int64(len(want)+listExcess),
func(key string, value []byte) {
if want[key] {
results[key] = string(value)
}
},
)
if err != nil {
if errors.Is(err, rados.ErrNotFound) {
util.ErrorLog(ctx, "omap not found (pool=%q, namespace=%q, name=%q): %v",