return ret;
}
+/**
+ * Get ordered listing of the objects in a bucket.
+ *
+ * max_p: maximum number of results to return
+ * bucket: bucket to list contents of
+ * prefix: only return results that match this prefix
+ * delim: do not include results that match this string.
+ * Any skipped results will have the matching portion of their name
+ * inserted in common_prefixes with a "true" mark.
+ * marker: if filled in, begin the listing with this object.
+ * end_marker: if filled in, end the listing with this object.
+ * result: the objects are put in here.
+ * common_prefixes: if delim is filled in, any matching prefixes are
+ * placed here.
+ * is_truncated: if number of objects in the bucket is bigger than
+ * max, then truncated.
+ */
int DB::Bucket::List::list_objects(const DoutPrefixProvider *dpp, int64_t max,
vector<rgw_bucket_dir_entry> *result,
map<string, bool> *common_prefixes, bool *is_truncated)
{
int ret = 0;
DB *store = target->get_store();
+ int64_t count = 0;
DBOpParams db_params = {};
store->InitializeParams(dpp, &db_params);
/* XXX: Handle whole marker? key -> name, instance, ns? */
db_params.op.obj.min_marker = params.marker.name;
db_params.op.obj.max_marker = params.end_marker.name;
+ db_params.op.obj.prefix = params.prefix + "%";
db_params.op.list_max_count = max + 1; /* +1 for next_marker */
ret = store->ProcessOp(dpp, "ListBucketObjects", &db_params);
goto out;
}
- if (db_params.op.obj.list_entries.size() >= (uint64_t)max) {
- *is_truncated = true;
- next_marker.name = db_params.op.obj.list_entries.back().key.name;
- next_marker.instance = db_params.op.obj.list_entries.back().key.instance;
- db_params.op.obj.list_entries.pop_back();
- }
for (auto& entry : db_params.op.obj.list_entries) {
+ if (count >= max) {
+ *is_truncated = true;
+ next_marker.name = entry.key.name;
+ next_marker.instance = entry.key.instance;
+ break;
+ }
+ if (!params.delim.empty()) {
+ const std::string& objname = entry.key.name;
+ const int delim_pos = objname.find(params.delim, params.prefix.size());
+ if (delim_pos >= 0) {
+ /* extract key -with trailing delimiter- for CommonPrefix */
+ const std::string& prefix_key =
+ objname.substr(0, delim_pos + params.delim.length());
+
+ if (common_prefixes &&
+ common_prefixes->find(prefix_key) == common_prefixes->end()) {
+ next_marker = prefix_key;
+ (*common_prefixes)[prefix_key] = true;
+ count++;
+ }
+ continue;
+ }
+ }
+
if (!params.end_marker.name.empty() &&
params.end_marker.name.compare(entry.key.name) <= 0) {
+ // should not include end_marker
*is_truncated = false;
break;
}
+ count++;
result->push_back(std::move(entry));
}
out:
}
int DB::Object::follow_olh(const DoutPrefixProvider *dpp,
- const RGWBucketInfo& bucket_info, RGWObjState *state,
+ const RGWBucketInfo& bucket_info, RGWObjState* state,
const rgw_obj& olh_obj, rgw_obj *target)
{
auto iter = state->attrset.find(RGW_ATTR_OLH_INFO);
int DB::Object::get_obj_state(const DoutPrefixProvider *dpp,
const RGWBucketInfo& bucket_info, const rgw_obj& obj,
- bool follow_olh, RGWObjState **state)
+ bool follow_olh, RGWObjState** state)
{
int ret = 0;
}
-int DB::Object::get_state(const DoutPrefixProvider *dpp, RGWObjState **pstate, bool follow_olh)
+int DB::Object::get_state(const DoutPrefixProvider *dpp, RGWObjState** pstate, bool follow_olh)
{
return get_obj_state(dpp, bucket_info, obj, follow_olh, pstate);
}
int DB::Object::Read::get_attr(const DoutPrefixProvider *dpp, const char *name, bufferlist& dest)
{
- RGWObjState *state;
+ RGWObjState* state;
int r = source->get_state(dpp, &state, true);
if (r < 0)
return r;
map<string, bufferlist>::iterator iter;
- RGWObjState *astate;
+ RGWObjState* astate;
/* XXX Read obj_id too */
int r = source->get_state(dpp, &astate, true);
bufferlist read_bl;
uint64_t max_chunk_size = store->get_max_chunk_size();
- RGWObjState *astate;
+ RGWObjState* astate;
int r = source->get_state(dpp, &astate, true);
if (r < 0)
return r;
static int _get_obj_iterate_cb(const DoutPrefixProvider *dpp,
const DB::raw_obj& read_obj, off_t obj_ofs,
off_t len, bool is_head_obj,
- RGWObjState *astate, void *arg)
+ RGWObjState* astate, void *arg)
{
struct db_get_obj_data* d = static_cast<struct db_get_obj_data*>(arg);
return d->store->get_obj_iterate_cb(dpp, read_obj, obj_ofs, len,
int DB::get_obj_iterate_cb(const DoutPrefixProvider *dpp,
const raw_obj& read_obj, off_t obj_ofs,
off_t len, bool is_head_obj,
- RGWObjState *astate, void *arg)
+ RGWObjState* astate, void *arg)
{
struct db_get_obj_data* d = static_cast<struct db_get_obj_data*>(arg);
bufferlist bl;
{
DB *store = get_store();
uint64_t len;
- RGWObjState *astate;
+ RGWObjState* astate;
int r = get_state(dpp, &astate, true);
if (r < 0) {
{
DB *store = target->get_store();
- RGWObjState *state = &obj_state;
+ RGWObjState* state = &obj_state;
map<string, bufferlist> *attrset;
DBOpParams params = {};
int ret = 0;
int DB::Object::Delete::delete_obj(const DoutPrefixProvider *dpp) {
int ret = 0;
DB *store = target->get_store();
- RGWObjState *astate;
+ RGWObjState* astate;
int r = target->get_state(dpp, &astate, true);
if (r < 0)
bufferlist head_data;
std::string min_marker;
std::string max_marker;
+ std::string prefix;
std::list<rgw_bucket_dir_entry> list_entries;
/* XXX: Maybe use std::vector instead of std::list */
};
static constexpr const char* head_data = ":head_data";
static constexpr const char* min_marker = ":min_marker";
static constexpr const char* max_marker = ":max_marker";
+ static constexpr const char* prefix = ":prefix";
/* Below used to update mp_parts obj name
* from meta object to src object on completion */
static constexpr const char* new_obj_name = ":new_obj_name";
ObjID, TailInstance, HeadPlacementRuleName, HeadPlacementRuleStorageClass, \
TailPlacementRuleName, TailPlacementStorageClass, \
ManifestPartObjs, ManifestPartRules, Omap, IsMultipart, MPPartsList, HeadData from '{}' \
- where BucketName = {} and ObjName > {} ORDER BY ObjName ASC LIMIT {}";
+ where BucketName = {} and ObjName >= {} and ObjName LIKE {} ORDER BY ObjName ASC LIMIT {}";
public:
virtual ~ListBucketObjectsOp() {}
params.object_table,
params.op.bucket.bucket_name,
params.op.obj.min_marker,
+ params.op.obj.prefix,
params.op.list_max_count);
}
};
TEST_F(DBStoreTest, GetObjectState) {
struct DBOpParams params = GlobalParams;
int ret = -1;
- RGWObjState state;
- RGWObjState *s = &state;
+ RGWObjState* s;
params.op.obj.state.obj.key.name = "object2";
params.op.obj.state.obj.key.instance = "inst2";
ret = op_target.get_obj_state(dpp, params.op.bucket.info, params.op.obj.state.obj,
false, &s);
ASSERT_EQ(ret, 0);
- ASSERT_EQ(state.size, 12);
- ASSERT_EQ(state.is_olh, false);
+ ASSERT_EQ(s->size, 12);
+ ASSERT_EQ(s->is_olh, false);
/* Recheck with get_state API */
ret = op_target.get_state(dpp, &s, false);
ASSERT_EQ(ret, 0);
- ASSERT_EQ(state.size, 12);
- ASSERT_EQ(state.is_olh, false);
+ ASSERT_EQ(s->size, 12);
+ ASSERT_EQ(s->is_olh, false);
}
TEST_F(DBStoreTest, ObjAttrs) {
TEST_F(DBStoreTest, DeleteObj) {
struct DBOpParams params = GlobalParams;
int ret = -1;
- RGWObjState state;
- RGWObjState *s = &state;
+ RGWObjState *s;
/* delete object2 */
params.op.obj.state.obj.key.name = "object2";