]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/dbstore: Create GC Thread to delete stale objects
authorSoumya Koduri <skoduri@redhat.com>
Wed, 26 Jan 2022 19:42:44 +0000 (01:12 +0530)
committerSoumya Koduri <skoduri@redhat.com>
Mon, 7 Feb 2022 02:09:55 +0000 (07:39 +0530)
Create a gc thread to cleanup the stale tail objects data

XXX: handle read + delete usecase, simple approach could be
to use locks or sqlite transactions in GC

Signed-off-by: Soumya Koduri <skoduri@redhat.com>
src/rgw/rgw_sal_dbstore.cc
src/rgw/store/dbstore/common/dbstore.cc
src/rgw/store/dbstore/common/dbstore.h
src/rgw/store/dbstore/sqlite/sqliteDB.cc
src/rgw/store/dbstore/sqlite/sqliteDB.h
src/rgw/store/dbstore/tests/dbstore_tests.cc

index 3e395fa3764ddd629006b1199d60df320cdde34f..bd90098731118c4622dfc625358682f99b72c55b 100644 (file)
@@ -41,7 +41,7 @@ namespace rgw::sal {
     int ret;
 
     buckets.clear();
-    ret = store->getDB()->list_buckets(dpp, info.user_id, marker, end_marker, max,
+    ret = store->getDB()->list_buckets(dpp, "", info.user_id, marker, end_marker, max,
         need_stats, &ulist, &is_truncated);
     if (ret < 0)
       return ret;
@@ -1901,6 +1901,11 @@ namespace rgw::sal {
       lc->start_processor();
     }
 
+    ret = db->createGC(dpp);
+    if (ret < 0) {
+      ldpp_dout(dpp, 0) <<"GC thread creation failed: ret = " << ret << dendl;
+    }
+
     return ret;
   }
 } // namespace rgw::sal
index b0ea5fafc7f39c6d6bf7a14ca76318b41376d65f..e74f278d5a61501f1fd30069645ff500ffec542f 100644 (file)
@@ -54,11 +54,29 @@ int DB::Initialize(string logfile, int loglevel)
   return ret;
 }
 
+int DB::createGC(const DoutPrefixProvider *dpp) {
+  int ret = 0;
+  /* create gc thread */
+
+  gc_worker = std::make_unique<DB::GC>(dpp, this);
+  gc_worker->create("db_gc");
+
+  return ret;
+}
+
+int DB::stopGC() {
+  if (gc_worker)
+    gc_worker->join();
+  return 0;
+}
+
 int DB::Destroy(const DoutPrefixProvider *dpp)
 {
   if (!db)
     return 0;
 
+  stopGC();
+
   closeDB(dpp);
 
 
@@ -140,6 +158,8 @@ DBOp *DB::getDBOp(const DoutPrefixProvider *dpp, string Op, struct DBOpParams *p
     return Ob->GetObjectData;
   if (!Op.compare("DeleteObjectData"))
     return Ob->DeleteObjectData;
+  if (!Op.compare("DeleteStaleObjectData"))
+    return Ob->DeleteStaleObjectData;
 
   return NULL;
 }
@@ -158,7 +178,7 @@ int DB::objectmapInsert(const DoutPrefixProvider *dpp, string bucket, class Obje
     // return error ?
     //
     // return success for now & delete the newly allocated ptr
-    ldpp_dout(dpp, 20)<<"Objectmap entry already exists for bucket("\
+    ldpp_dout(dpp, 30)<<"Objectmap entry already exists for bucket("\
       <<bucket<<"). Not inserted " << dendl;
     delete ptr;
     return 0;
@@ -558,7 +578,8 @@ out:
   return ret;
 }
 
-int DB::list_buckets(const DoutPrefixProvider *dpp, const rgw_user& user,
+int DB::list_buckets(const DoutPrefixProvider *dpp, const std::string& query_str,
+    rgw_user& user,
     const string& marker,
     const string& end_marker,
     uint64_t max,
@@ -575,6 +596,7 @@ int DB::list_buckets(const DoutPrefixProvider *dpp, const rgw_user& user,
   params.op.bucket.min_marker = marker;
   params.op.bucket.max_marker = end_marker;
   params.op.list_max_count = max;
+  params.op.query_str = query_str;
 
   ret = ProcessOp(dpp, "ListUserBuckets", &params);
 
@@ -597,6 +619,12 @@ int DB::list_buckets(const DoutPrefixProvider *dpp, const rgw_user& user,
     }
     buckets->add(std::move(entry));
   }
+
+  if (query_str == "all") {
+    // userID/OwnerID may have changed. Update it.
+    user.id = params.op.bucket.info.owner.id;
+  }
+
 out:
   return ret;
 }
@@ -1114,6 +1142,7 @@ int DB::raw_obj::write(const DoutPrefixProvider *dpp, int64_t ofs, int64_t write
   unsigned write_len = std::min((uint64_t)bl.length() - write_ofs, len);
   bl.begin(write_ofs).copy(write_len, params.op.obj_data.data);
   params.op.obj_data.size = params.op.obj_data.data.length();
+  params.op.obj.state.mtime = real_clock::now();
 
   ret = db->ProcessOp(dpp, "PutObjectData", &params);
 
@@ -1544,9 +1573,8 @@ int DB::Object::Write::prepare(const DoutPrefixProvider* dpp)
     gen_rand_alphanumeric(store->ctx(), buf, sizeof(buf) - 1);
     target->obj_id = target->obj.key.name + "." + buf;
   }
-  
-  ret = 0;
 
+  ret = 0;
   return ret;
 }
 
@@ -1710,6 +1738,7 @@ int DB::Object::Write::_do_write_meta(const DoutPrefixProvider *dpp,
 
   /* XXX: handle multipart */
   params.op.query_str = "meta";
+  params.op.obj.obj_id = target->obj_id;
   ret = store->ProcessOp(dpp, "PutObject", &params);
 
   if (ret) {
@@ -1968,5 +1997,79 @@ out:
   return ret;
 }
 
+int DB::delete_stale_objs(const DoutPrefixProvider *dpp, const std::string& bucket,
+                          uint32_t min_wait) {
+  DBOpParams params = {};
+  int ret = -1;
+
+  params.op.bucket.info.bucket.name = bucket;
+  /* Verify if bucket exists.
+   * XXX: This is needed for now to create objectmap of bucket
+   * in SQLGetBucket
+   */
+  InitializeParams(dpp, "GetBucket", &params);
+  ret = ProcessOp(dpp, "GetBucket", &params);
+  if (ret) {
+    ldpp_dout(dpp, 0) << "In GetBucket failed err:(" <<ret<<")" << dendl;
+  }
+
+  ldpp_dout(dpp, 30) << " Deleting stale_objs of bucket( " << bucket <<")" << dendl;
+  /* XXX: handle reads racing with delete here. Simple approach is maybe
+   * to use locks or sqlite transactions.
+   */
+  InitializeParams(dpp, "DeleteStaleObjectData", &params);
+  params.op.obj.state.mtime = (real_clock::now() + make_timespan(min_wait));
+  ret = ProcessOp(dpp, "DeleteStaleObjectData", &params);
+  if (ret) {
+    ldpp_dout(dpp, 0) << "In DeleteStaleObjectData failed err:(" <<ret<<")" << dendl;
+  }
+
+  return ret;
+}
+
+void *DB::GC::entry() {
+  do {
+    ldpp_dout(dpp, 2) << " DB GC started " << dendl;
+    int max = 100;
+    RGWUserBuckets buckets;
+    bool is_truncated = false;
+
+    do {
+      std::string& marker = bucket_marker;
+      rgw_user user;
+      user.id = user_marker;
+      buckets.clear();
+
+      int r = db->list_buckets(dpp, "all", user, marker, string(),
+                       max, false, &buckets, &is_truncated);
+      if (r < 0) { //do nothing? retry later ?
+        break;
+      }
+
+      for (const auto& ent : buckets.get_buckets()) {
+        const std::string &bname = ent.first;
+
+        r = db->delete_stale_objs(dpp, bname, gc_obj_min_wait);
+
+        if (r < 0) { //do nothing? skip to next entry?
+         ldpp_dout(dpp, 2) << " delete_stale_objs failed for bucket( " << bname <<")" << dendl;
+        }
+        bucket_marker = bname;
+        user_marker = user.id;
+
+        /* XXX: If using locks, unlock here and reacquire in the next iteration */
+        std::this_thread::sleep_for(std::chrono::milliseconds(10));
+      }
+    } while(is_truncated);
+
+    bucket_marker.clear();
+    std::this_thread::sleep_for(std::chrono::milliseconds(gc_interval));
+
+  } while(1);
+
+  return nullptr;
+}
+
 } } // namespace rgw::store
 
index 1f86a6149e6f3d80c4714479e2da97074fea8702..2a0e0bc273637de598dcd39141ca415a9f49e98b 100644 (file)
@@ -371,6 +371,7 @@ class ObjectOp {
     class UpdateObjectDataOp *UpdateObjectData;
     class GetObjectDataOp *GetObjectData;
     class DeleteObjectDataOp *DeleteObjectData;
+    class DeleteStaleObjectDataOp *DeleteStaleObjectData;
 
     virtual int InitializeObjectOps(std::string db_name, const DoutPrefixProvider *dpp) { return 0; }
     virtual int FreeObjectOps(const DoutPrefixProvider *dpp) { return 0; }
@@ -426,8 +427,11 @@ class DBOp {
 
     const std::string CreateBucketTableQ =
       /* Corresponds to rgw::sal::Bucket
+       *  
+       *  For now only BucketName is made Primary key. Since buckets should
+       *  be unique across users in rgw, OwnerID is not made part of primary key.
+       *  However it is still referenced as foreign key
        *
-       *  For now only BucketName is made Primary key.
        *  If multiple tenants are stored in single .db handle, should
        *  make both (BucketName, Tenant) as Primary Key. Also should
        *  reference (UserID, Tenant) as Foreign key.
@@ -582,6 +586,7 @@ class DBOp {
       PartNum  INTEGER NOT NULL, \
       Offset   INTEGER, \
       Size      INTEGER, \
+      Mtime  BLOB,       \
       Data     BLOB,             \
       PRIMARY KEY (ObjName, BucketName, ObjInstance, ObjID, MultipartPartStr, PartNum), \
       FOREIGN KEY (BucketName) \
@@ -925,13 +930,31 @@ class ListUserBucketsOp: virtual public DBOp {
                           SyncPolicyInfoGroups, BucketAttrs, BucketVersion, BucketVersionTag, Mtime \
                           FROM '{}' WHERE OwnerID = {} AND BucketName > {} ORDER BY BucketName ASC LIMIT {}";
 
+    /* BucketNames are unique across users. Hence userid/OwnerID is not used as
+     * marker or for ordering here in the below query 
+     */
+    const std::string AllQuery = "SELECT  \
+                          BucketName, Tenant, Marker, BucketID, Size, SizeRounded, CreationTime, \
+                          Count, PlacementName, PlacementStorageClass, OwnerID, Flags, Zonegroup, \
+                          HasInstanceObj, Quota, RequesterPays, HasWebsite, WebsiteConf, \
+                          SwiftVersioning, SwiftVerLocation, \
+                          MdsearchConfig, NewBucketInstanceID, ObjectLock, \
+                          SyncPolicyInfoGroups, BucketAttrs, BucketVersion, BucketVersionTag, Mtime \
+                          FROM '{}' WHERE BucketName > {} ORDER BY BucketName ASC LIMIT {}";
+
   public:
     virtual ~ListUserBucketsOp() {}
 
     std::string Schema(DBOpPrepareParams &params) {
-      return fmt::format(Query.c_str(), params.bucket_table.c_str(),
+      if (params.op.query_str == "all") {
+        return fmt::format(AllQuery.c_str(), params.bucket_table.c_str(),
+          params.op.bucket.min_marker.c_str(),
+          params.op.list_max_count.c_str());
+      } else {
+        return fmt::format(Query.c_str(), params.bucket_table.c_str(),
           params.op.user.user_id.c_str(), params.op.bucket.min_marker.c_str(),
           params.op.list_max_count.c_str());
+      }
     }
 };
 
@@ -1148,8 +1171,8 @@ class PutObjectDataOp: virtual public DBOp {
   private:
     const std::string Query =
       "INSERT OR REPLACE INTO '{}' \
-      (ObjName, ObjInstance, ObjNS, BucketName, ObjID, MultipartPartStr, PartNum, Offset, Size, Data) \
-      VALUES ({}, {}, {}, {}, {}, {}, {}, {}, {}, {})";
+      (ObjName, ObjInstance, ObjNS, BucketName, ObjID, MultipartPartStr, PartNum, Offset, Size, Mtime, Data) \
+      VALUES ({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {})";
 
   public:
     virtual ~PutObjectDataOp() {}
@@ -1165,6 +1188,7 @@ class PutObjectDataOp: virtual public DBOp {
           params.op.obj_data.part_num,
           params.op.obj_data.offset.c_str(),
           params.op.obj_data.size,
+          params.op.obj.mtime,
           params.op.obj_data.data.c_str());
     }
 };
@@ -1195,7 +1219,7 @@ class GetObjectDataOp: virtual public DBOp {
   private:
     const std::string Query =
       "SELECT  \
-      ObjName, ObjInstance, ObjNS, BucketName, ObjID, MultipartPartStr, PartNum, Offset, Size, Data \
+      ObjName, ObjInstance, ObjNS, BucketName, ObjID, MultipartPartStr, PartNum, Offset, Size, Mtime, Data \
       from '{}' where BucketName = {} and ObjName = {} and ObjInstance = {} and ObjID = {} ORDER BY MultipartPartStr, PartNum";
 
   public:
@@ -1229,6 +1253,23 @@ class DeleteObjectDataOp: virtual public DBOp {
     }
 };
 
+class DeleteStaleObjectDataOp: virtual public DBOp {
+  private:
+    const std::string Query =
+      "DELETE from '{}' WHERE (ObjName, ObjInstance, ObjID) NOT IN (SELECT s.ObjName, s.ObjInstance, s.ObjID from '{}' as s INNER JOIN '{}' USING (ObjName, BucketName, ObjInstance, ObjID)) and Mtime > {}";
+
+  public:
+    virtual ~DeleteStaleObjectDataOp() {}
+
+    std::string Schema(DBOpPrepareParams &params) {
+      return fmt::format(Query.c_str(),
+          params.objectdata_table.c_str(),
+          params.objectdata_table.c_str(),
+          params.object_table.c_str(),
+          params.op.obj.mtime);
+    }
+};
+
 class InsertLCEntryOp: virtual public DBOp {
   private:
     const std::string Query =
@@ -1497,7 +1538,8 @@ class DB {
     int next_bucket_id() { return ++max_bucket_id; };
 
     int remove_bucket(const DoutPrefixProvider *dpp, const RGWBucketInfo info);
-    int list_buckets(const DoutPrefixProvider *dpp, const rgw_user& user,
+    int list_buckets(const DoutPrefixProvider *dpp, const std::string& query_str,
+        rgw_user& user,
         const std::string& marker,
         const std::string& end_marker,
         uint64_t max,
@@ -1591,6 +1633,31 @@ class DB {
       int write(const DoutPrefixProvider *dpp, int64_t ofs, int64_t write_ofs, uint64_t len, bufferlist& bl);
     };
 
+    class GC : public Thread {
+      const DoutPrefixProvider *dpp;
+      DB *db;
+      /* Default time interval for GC 
+       * XXX: Make below options configurable
+       *
+       * gc_interval: The time between successive gc thread runs
+       * gc_obj_min_wait: Min. time to wait before deleting any data post its creation.
+       *                    
+       */
+      uint32_t gc_interval = 24*60*60*10; //msec ; default: 24*60*60*10
+      uint32_t gc_obj_min_wait = 600; //600sec default
+      std::string bucket_marker;
+      std::string user_marker;
+
+    public:
+      GC(const DoutPrefixProvider *_dpp, DB* _db) :
+            dpp(_dpp), db(_db) {}
+
+      void *entry() override;
+      friend class DB;
+    };
+    std::unique_ptr<DB::GC> gc_worker;
+
     class Bucket {
       friend class DB;
       DB* store;
@@ -1849,6 +1916,10 @@ class DB {
     int rm_entry(const std::string& oid, const rgw::sal::Lifecycle::LCEntry& entry);
     int get_head(const std::string& oid, rgw::sal::Lifecycle::LCHead& head);
     int put_head(const std::string& oid, const rgw::sal::Lifecycle::LCHead& head);
+    int delete_stale_objs(const DoutPrefixProvider *dpp, const std::string& bucket,
+                          uint32_t min_wait);
+    int createGC(const DoutPrefixProvider *_dpp);
+    int stopGC();
 };
 
 struct db_get_obj_data {
index f27db5f64cd2be22ad32a6c64ec3b4f02b2b7e5c..ee6eb9667f3625b5c304dbd579aec15071291d17 100644 (file)
@@ -280,6 +280,7 @@ enum GetObjectData {
   PartNum,
   Offset,
   ObjDataSize,
+  ObjDataMtime,
   ObjData
 };
 
@@ -493,6 +494,7 @@ static int get_objectdata(const DoutPrefixProvider *dpp, DBOpInfo &op, sqlite3_s
   op.obj_data.offset = sqlite3_column_int(stmt, Offset);
   op.obj_data.size = sqlite3_column_int(stmt, ObjDataSize);
   op.obj_data.multipart_part_str = (const char*)sqlite3_column_text(stmt, MultipartPartStr);
+  SQL_DECODE_BLOB_PARAM(dpp, stmt, ObjDataMtime, op.obj.state.mtime, sdb);
   SQL_DECODE_BLOB_PARAM(dpp, stmt, ObjData, op.obj_data.data, sdb);
 
   return 0;
@@ -991,6 +993,7 @@ int SQLObjectOp::InitializeObjectOps(string db_name, const DoutPrefixProvider *d
   UpdateObjectData = new SQLUpdateObjectData(sdb, db_name, cct);
   GetObjectData = new SQLGetObjectData(sdb, db_name, cct);
   DeleteObjectData = new SQLDeleteObjectData(sdb, db_name, cct);
+  DeleteStaleObjectData = new SQLDeleteStaleObjectData(sdb, db_name, cct);
 
   return 0;
 }
@@ -1005,6 +1008,7 @@ int SQLObjectOp::FreeObjectOps(const DoutPrefixProvider *dpp)
   delete UpdateObjectData;
   delete GetObjectData;
   delete DeleteObjectData;
+  delete DeleteStaleObjectData;
 
   return 0;
 }
@@ -1284,6 +1288,7 @@ int SQLInsertBucket::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *para
   int rc = 0;
   struct DBOpPrepareParams p_params = PrepareParams;
 
+  // user_id here is copied as OwnerID in the bucket table.
   SQL_BIND_INDEX(dpp, stmt, index, p_params.op.user.user_id.c_str(), sdb);
   SQL_BIND_TEXT(dpp, stmt, index, params->op.user.uinfo.user_id.id.c_str(), sdb);
 
@@ -1646,7 +1651,12 @@ int SQLListUserBuckets::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams
 
   p_params.bucket_table = params->bucket_table;
 
-  SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareListUserBuckets");
+  p_params.op.query_str = params->op.query_str;
+  if (params->op.query_str == "all") { 
+    SQL_PREPARE(dpp, p_params, sdb, all_stmt, ret, "PrepareListUserBuckets");
+  }else {
+    SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareListUserBuckets");
+  }
 
 out:
   return ret;
@@ -1657,15 +1667,24 @@ int SQLListUserBuckets::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *p
   int index = -1;
   int rc = 0;
   struct DBOpPrepareParams p_params = PrepareParams;
+  sqlite3_stmt** pstmt = NULL; // Prepared statement
 
-  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.user.user_id.c_str(), sdb);
-  SQL_BIND_TEXT(dpp, stmt, index, params->op.user.uinfo.user_id.id.c_str(), sdb);
+  if (params->op.query_str == "all") { 
+    pstmt = &all_stmt;
+  } else { 
+    pstmt = &stmt;
+  }
+
+  if (params->op.query_str != "all") { 
+    SQL_BIND_INDEX(dpp, *pstmt, index, p_params.op.user.user_id.c_str(), sdb);
+    SQL_BIND_TEXT(dpp, *pstmt, index, params->op.user.uinfo.user_id.id.c_str(), sdb);
+  }
 
-  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.bucket.min_marker.c_str(), sdb);
-  SQL_BIND_TEXT(dpp, stmt, index, params->op.bucket.min_marker.c_str(), sdb);
+  SQL_BIND_INDEX(dpp, *pstmt, index, p_params.op.bucket.min_marker.c_str(), sdb);
+  SQL_BIND_TEXT(dpp, *pstmt, index, params->op.bucket.min_marker.c_str(), sdb);
 
-  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.list_max_count.c_str(), sdb);
-  SQL_BIND_INT(dpp, stmt, index, params->op.list_max_count, sdb);
+  SQL_BIND_INDEX(dpp, *pstmt, index, p_params.op.list_max_count.c_str(), sdb);
+  SQL_BIND_INT(dpp, *pstmt, index, params->op.list_max_count, sdb);
 
 out:
   return rc;
@@ -1675,7 +1694,11 @@ int SQLListUserBuckets::Execute(const DoutPrefixProvider *dpp, struct DBOpParams
 {
   int ret = -1;
 
-  SQL_EXECUTE(dpp, params, stmt, list_bucket);
+  if (params->op.query_str == "all") { 
+    SQL_EXECUTE(dpp, params, all_stmt, list_bucket);
+  } else {
+    SQL_EXECUTE(dpp, params, stmt, list_bucket);
+  }
 out:
   return ret;
 }
@@ -2347,6 +2370,9 @@ int SQLPutObjectData::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *par
 
   SQL_BIND_TEXT(dpp, stmt, index, params->op.obj_data.multipart_part_str.c_str(), sdb);
 
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.obj.mtime.c_str(), sdb);
+  SQL_ENCODE_BLOB_PARAM(dpp, stmt, index, params->op.obj.state.mtime, sdb);
+
 out:
   return rc;
 }
@@ -2554,6 +2580,56 @@ out:
   return ret;
 }
 
+int SQLDeleteStaleObjectData::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+  struct DBOpPrepareParams p_params = PrepareParams;
+  struct DBOpParams copy = *params;
+  string bucket_name = params->op.bucket.info.bucket.name;
+
+  if (!*sdb) {
+    ldpp_dout(dpp, 0)<<"In SQLDeleteStaleObjectData - no db" << dendl;
+    goto out;
+  }
+
+  if (p_params.object_table.empty()) {
+    p_params.object_table = getObjectTable(bucket_name);
+  }
+  if (p_params.objectdata_table.empty()) {
+    p_params.objectdata_table = getObjectDataTable(bucket_name);
+  }
+  params->object_table = p_params.object_table;
+  params->objectdata_table = p_params.objectdata_table;
+  (void)createObjectDataTable(dpp, params);
+
+  SQL_PREPARE(dpp, p_params, sdb, stmt, ret, "PrepareDeleteStaleObjectData");
+
+out:
+  return ret;
+}
+
+int SQLDeleteStaleObjectData::Bind(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int index = -1;
+  int rc = 0;
+  struct DBOpPrepareParams p_params = PrepareParams;
+
+  SQL_BIND_INDEX(dpp, stmt, index, p_params.op.obj.mtime.c_str(), sdb);
+  SQL_ENCODE_BLOB_PARAM(dpp, stmt, index, params->op.obj.state.mtime, sdb);
+
+out:
+  return rc;
+}
+
+int SQLDeleteStaleObjectData::Execute(const DoutPrefixProvider *dpp, struct DBOpParams *params)
+{
+  int ret = -1;
+
+  SQL_EXECUTE(dpp, params, stmt, NULL);
+out:
+  return ret;
+}
+
 int SQLInsertLCEntry::Prepare(const DoutPrefixProvider *dpp, struct DBOpParams *params)
 {
   int ret = -1;
index dd56ab1f9ec669988faee0ec1166d9318c5765f6..b83296c5a8605a1a2e0fe6cddc789752978f3595 100644 (file)
@@ -213,12 +213,15 @@ class SQLListUserBuckets : public SQLiteDB, public ListUserBucketsOp {
   private:
     sqlite3 **sdb = NULL;
     sqlite3_stmt *stmt = NULL; // Prepared statement
+    sqlite3_stmt *all_stmt = NULL; // Prepared statement
 
   public:
     SQLListUserBuckets(void **db, std::string db_name, CephContext *cct) : SQLiteDB((sqlite3 *)(*db), db_name, cct), sdb((sqlite3 **)db) {}
     ~SQLListUserBuckets() {
       if (stmt)
         sqlite3_finalize(stmt);
+      if (all_stmt)
+        sqlite3_finalize(all_stmt);
     }
     int Prepare(const DoutPrefixProvider *dpp, DBOpParams *params);
     int Execute(const DoutPrefixProvider *dpp, DBOpParams *params);
@@ -395,6 +398,24 @@ class SQLDeleteObjectData : public SQLiteDB, public DeleteObjectDataOp {
     int Bind(const DoutPrefixProvider *dpp, DBOpParams *params);
 };
 
+class SQLDeleteStaleObjectData : public SQLiteDB, public DeleteStaleObjectDataOp {
+  private:
+    sqlite3 **sdb = NULL;
+    sqlite3_stmt *stmt = NULL; // Prepared statement
+
+  public:
+    SQLDeleteStaleObjectData(void **db, std::string db_name, CephContext *cct) : SQLiteDB((sqlite3 *)(*db), db_name, cct), sdb((sqlite3 **)db) {}
+    SQLDeleteStaleObjectData(sqlite3 **sdbi, std::string db_name, CephContext *cct) : SQLiteDB(*sdbi, db_name, cct), sdb(sdbi) {}
+
+    ~SQLDeleteStaleObjectData() {
+      if (stmt)
+        sqlite3_finalize(stmt);
+    }
+    int Prepare(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Execute(const DoutPrefixProvider *dpp, DBOpParams *params);
+    int Bind(const DoutPrefixProvider *dpp, DBOpParams *params);
+};
+
 class SQLInsertLCEntry : public SQLiteDB, public InsertLCEntryOp {
   private:
     sqlite3 **sdb = NULL;
index 608def7e83a4d6d31099f75bcecdc4350d7c0308..481ad5be4c28eb5826999c33abe50531c936bbf8 100644 (file)
@@ -390,19 +390,6 @@ TEST_F(DBStoreTest, UpdateBucketAttrs) {
   ASSERT_EQ(objv.read_version.ver, 2);
 }
 
-TEST_F(DBStoreTest, BucketChown) {
-  int ret = -1;
-  RGWBucketInfo info;
-  rgw_user user;
-  user.id = "user_id2";
-
-  info.bucket.name = "bucket1";
-
-  ret = db->update_bucket(dpp, "owner", info, false, &user, nullptr, &bucket_mtime, nullptr);
-  ASSERT_EQ(ret, 0);
-  ASSERT_EQ(info.objv_tracker.read_version.ver, 3);
-}
-
 TEST_F(DBStoreTest, UpdateBucketInfo) {
   struct DBOpParams params = GlobalParams;
   int ret = -1;
@@ -418,13 +405,14 @@ TEST_F(DBStoreTest, UpdateBucketInfo) {
   info.bucket.marker = "marker2";
   ret = db->update_bucket(dpp, "info", info, false, nullptr, nullptr, &bucket_mtime, nullptr);
   ASSERT_EQ(ret, 0);
-  ASSERT_EQ(info.objv_tracker.read_version.ver, 4);
+  ASSERT_EQ(info.objv_tracker.read_version.ver, 3);
 }
 
 TEST_F(DBStoreTest, GetBucket) {
   struct DBOpParams params = GlobalParams;
   int ret = -1;
 
+  params.op.bucket.info.bucket.name = "bucket1";
   ret = db->ProcessOp(dpp, "GetBucket", &params);
   ASSERT_EQ(ret, 0);
   ASSERT_EQ(params.op.bucket.info.bucket.name, "bucket1");
@@ -434,10 +422,10 @@ TEST_F(DBStoreTest, GetBucket) {
   ASSERT_EQ(params.op.bucket.ent.bucket.name, "bucket1");
   ASSERT_EQ(params.op.bucket.ent.bucket.tenant, "tenant");
   ASSERT_EQ(params.op.bucket.info.has_instance_obj, false);
-  ASSERT_EQ(params.op.bucket.info.objv_tracker.read_version.ver, 4);
+  ASSERT_EQ(params.op.bucket.info.objv_tracker.read_version.ver, 3);
   ASSERT_EQ(params.op.bucket.info.objv_tracker.read_version.tag, "read_tag");
   ASSERT_EQ(params.op.bucket.mtime, bucket_mtime);
-  ASSERT_EQ(params.op.bucket.info.owner.id, "user_id2");
+  ASSERT_EQ(params.op.bucket.info.owner.id, "user_id1");
   bufferlist k, k2;
   string acl;
   map<std::string, bufferlist>::iterator it2 = params.op.bucket.bucket_attrs.begin();
@@ -450,35 +438,6 @@ TEST_F(DBStoreTest, GetBucket) {
   ASSERT_EQ(acl, "attrs2");
 }
 
-TEST_F(DBStoreTest, RemoveBucketAPI) {
-  int ret = -1;
-  RGWBucketInfo info;
-
-  info.bucket.name = "bucket1";
-
-  ret = db->remove_bucket(dpp, info);
-  ASSERT_EQ(ret, 0);
-}
-
-TEST_F(DBStoreTest, RemoveUserAPI) {
-  int ret = -1;
-  RGWUserInfo uinfo;
-  RGWObjVersionTracker objv;
-
-  uinfo.user_id.tenant = "tenant";
-  uinfo.user_id.id = "user_id2";
-
-  /* invalid version number...should fail */
-  objv.read_version.ver = 4;
-  ret = db->remove_user(dpp, uinfo, &objv);
-  ASSERT_EQ(ret, -125);
-
-  /* invalid version number...should fail */
-  objv.read_version.ver = 2;
-  ret = db->remove_user(dpp, uinfo, &objv);
-  ASSERT_EQ(ret, 0);
-}
-
 TEST_F(DBStoreTest, CreateBucket) {
   struct DBOpParams params = GlobalParams;
   int ret = -1;
@@ -564,7 +523,8 @@ TEST_F(DBStoreTest, ListUserBuckets) {
   marker1 = "";
   do {
     is_truncated = false;
-    ret = db->list_buckets(dpp, owner, marker1, "", max, need_stats, &ulist, &is_truncated);
+    ret = db->list_buckets(dpp, "", owner, marker1, "", max, need_stats, &ulist,
+          &is_truncated);
     ASSERT_EQ(ret, 0);
 
     cout << "marker1 :" << marker1 << "\n";
@@ -586,6 +546,19 @@ TEST_F(DBStoreTest, ListUserBuckets) {
   } while(is_truncated);
 }
 
+TEST_F(DBStoreTest, BucketChown) {
+  int ret = -1;
+  RGWBucketInfo info;
+  rgw_user user;
+  user.id = "user_id2";
+
+  info.bucket.name = "bucket5";
+
+  ret = db->update_bucket(dpp, "owner", info, false, &user, nullptr, &bucket_mtime, nullptr);
+  ASSERT_EQ(ret, 0);
+  ASSERT_EQ(info.objv_tracker.read_version.ver, 3);
+}
+
 TEST_F(DBStoreTest, ListAllBuckets) {
   struct DBOpParams params = GlobalParams;
   int ret = -1;
@@ -594,6 +567,72 @@ TEST_F(DBStoreTest, ListAllBuckets) {
   ASSERT_EQ(ret, 0);
 }
 
+TEST_F(DBStoreTest, ListAllBuckets2) {
+  struct DBOpParams params = GlobalParams;
+  int ret = -1;
+  rgw_user owner;
+  int max = 2;
+  bool need_stats = true;
+  bool is_truncated = false;
+  RGWUserBuckets ulist;
+
+  marker1 = "";
+  do {
+    is_truncated = false;
+    ret = db->list_buckets(dpp, "all", owner, marker1, "", max, need_stats, &ulist,
+          &is_truncated);
+    ASSERT_EQ(ret, 0);
+
+    cout << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \n";
+    cout << "ownerID : " << owner.id << "\n";
+    cout << "marker1 :" << marker1 << "\n";
+
+    cout << "is_truncated :" << is_truncated << "\n";
+
+    for (const auto& ent: ulist.get_buckets()) {
+      RGWBucketEnt e = ent.second;
+      cout << "###################### \n";
+      cout << "ent.bucket.id : " << e.bucket.name << "\n";
+      cout << "ent.bucket.marker : " << e.bucket.marker << "\n";
+      cout << "ent.bucket.bucket_id : " << e.bucket.bucket_id << "\n";
+      cout << "ent.size : " << e.size << "\n";
+      cout << "ent.rule.name : " << e.placement_rule.name << "\n";
+
+      marker1 = e.bucket.name;
+    }
+    ulist.clear();
+  } while(is_truncated);
+}
+
+TEST_F(DBStoreTest, RemoveBucketAPI) {
+  int ret = -1;
+  RGWBucketInfo info;
+
+  info.bucket.name = "bucket5";
+
+  ret = db->remove_bucket(dpp, info);
+  ASSERT_EQ(ret, 0);
+}
+
+TEST_F(DBStoreTest, RemoveUserAPI) {
+  int ret = -1;
+  RGWUserInfo uinfo;
+  RGWObjVersionTracker objv;
+
+  uinfo.user_id.tenant = "tenant";
+  uinfo.user_id.id = "user_id2";
+
+  /* invalid version number...should fail */
+  objv.read_version.ver = 4;
+  ret = db->remove_user(dpp, uinfo, &objv);
+  ASSERT_EQ(ret, -125);
+
+  /* invalid version number...should fail */
+  objv.read_version.ver = 2;
+  ret = db->remove_user(dpp, uinfo, &objv);
+  ASSERT_EQ(ret, 0);
+}
+
 TEST_F(DBStoreTest, PutObject) {
   struct DBOpParams params = GlobalParams;
   int ret = -1;