]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tools/bluestore: Add command 'trim' to ceph-bluestore-tool 57369/head
authoryite.gu <yitegu0@gmail.com>
Thu, 9 May 2024 06:31:58 +0000 (14:31 +0800)
committeryite.gu <yitegu0@gmail.com>
Thu, 16 May 2024 01:48:40 +0000 (09:48 +0800)
Add command 'trim' to ceph-bluestore-tool.

Co-authored-by: Igor Fedotov <igor.fedotov@croit.io>
Signed-off-by: Yite Gu <yitegu0@gmail.com>
doc/man/8/ceph-bluestore-tool.rst
src/blk/BlockDevice.h
src/blk/kernel/KernelDevice.cc
src/os/bluestore/BlueFS.cc
src/os/bluestore/BlueFS.h
src/os/bluestore/BlueStore.cc
src/os/bluestore/BlueStore.h
src/os/bluestore/bluestore_tool.cc

index 634d3a8bb6eb05b0660c9c231ba75cd087d6c35d..fa25facedce0a58086d84513d76da83ee658cd98 100644 (file)
@@ -29,6 +29,7 @@ Synopsis
 | **ceph-bluestore-tool** free-dump|free-score --path *osd path* [ --allocator block/bluefs-wal/bluefs-db/bluefs-slow ]
 | **ceph-bluestore-tool** reshard --path *osd path* --sharding *new sharding* [ --sharding-ctrl *control string* ]
 | **ceph-bluestore-tool** show-sharding --path *osd path*
+| **ceph-bluestore-tool** trim --path *osd path*
 
 
 Description
@@ -131,6 +132,13 @@ Commands
 
    Show sharding that is currently applied to BlueStore's RocksDB.
 
+:command: `trim` --path *osd path*
+
+   An SSD that has been used heavily may experience performance degradation.
+   This operation uses TRIM / discard to free unused blocks from BlueStore and BlueFS block devices,
+   and allows the drive to perform more efficient internal housekeeping.
+   If BlueStore runs with discard enabled, this option may not be useful.
+
 Options
 =======
 
index 6c55646fc76df8d5594bbb66d1a7729e9a0966c5..c45c0759c216c57005cb3f74b1aded5299c6eca9 100644 (file)
@@ -233,6 +233,7 @@ public:
   uint64_t get_size() const { return size; }
   uint64_t get_block_size() const { return block_size; }
   uint64_t get_optimal_io_size() const { return optimal_io_size; }
+  bool is_discard_supported() const { return support_discard; }
 
   /// hook to provide utilization of thinly-provisioned device
   virtual int get_ebd_state(ExtBlkDevState &state) const {
index 6337292f5dec25e95766e5db79b1e9cc9dcff8ad..e77d17e0333092a97b3ee369423ffed56f05841f 100644 (file)
@@ -1116,8 +1116,8 @@ int KernelDevice::_discard(uint64_t offset, uint64_t len)
     return 0;
   }
   dout(10) << __func__
-          << " 0x" << std::hex << offset << "~" << len << std::dec
-          << dendl;
+           << " 0x" << std::hex << offset << "~" << len << std::dec
+           << dendl;
   r = BlkDev{fd_directs[WRITE_LIFE_NOT_SET]}.discard((int64_t)offset, (int64_t)len);
   return r;
 }
index a8b1fb25ee85ee09528b080231e1813658949cf6..4a287ec3545b345ed15204bd58c2f5a6f3f2144c 100644 (file)
@@ -4738,6 +4738,37 @@ size_t BlueFS::probe_alloc_avail(int dev, uint64_t alloc_size)
   }
   return total;
 }
+
+void BlueFS::trim_free_space(const string& type, std::ostream& outss)
+{
+  unsigned bdev_id;
+  if(type == "bdev-wal") {
+    bdev_id = BDEV_WAL;
+  } else if (type == "bdev-db") {
+    bdev_id = BDEV_DB;
+  } else {
+    derr << __func__ << " unknown bdev type " << type << dendl;
+    return;
+  }
+  auto iterated_allocation = [&](size_t off, size_t len) {
+    ceph_assert(len > 0);
+    interval_set<uint64_t> to_discard;
+    to_discard.union_insert(off, len);
+    bdev[bdev_id]->try_discard(to_discard, false);
+  };
+  if (!bdev[bdev_id]) {
+    outss << "device " << type << " is not configured";
+    return;
+  }
+  if (alloc[bdev_id] && !is_shared_alloc(bdev_id)) {
+    if (!bdev[bdev_id]->is_discard_supported()) {
+      outss << "device " << type << " does not support trim";
+      return;
+    }
+    alloc[bdev_id]->foreach(iterated_allocation);
+    outss << "device " << type << " trim done";
+  }
+}
 // ===============================================
 // OriginalVolumeSelector
 
index 86fb3cc882e1e4c2c5cd9d98d0d98e246734ea7a..f57deac57063689be19928becd633a1d83b7b33c 100644 (file)
@@ -778,6 +778,7 @@ public:
   }
   uint64_t debug_get_dirty_seq(FileWriter *h);
   bool debug_get_is_dev_dirty(FileWriter *h, uint8_t dev);
+  void trim_free_space(const std::string& type, std::ostream& outss);
 
 private:
   // Wrappers for BlockDevice::read(...) and BlockDevice::read_random(...)
index 286dad7d3def54174aceb4ccb6e7168e64794ffe..fec8a9ceb34005c048ba4b93c85f6de854a3b799 100644 (file)
@@ -8605,6 +8605,26 @@ int BlueStore::dump_bluefs_sizes(ostream& out)
   return r;
 }
 
+void BlueStore::trim_free_space(const string& type, std::ostream& outss)
+{
+  auto iterated_allocation = [&](size_t off, size_t len) {
+    ceph_assert(len > 0);
+    interval_set<uint64_t> to_discard;
+    to_discard.union_insert(off, len);
+    bdev->try_discard(to_discard, false);
+  };
+  if (type == "bdev-block") {
+    if (!bdev->is_discard_supported()) {
+      outss << "device " << type << " does not support trim";
+      return;
+    }
+    shared_alloc.a->foreach(iterated_allocation);
+    outss << "device " << type << " trim done";
+  } else {
+    bluefs->trim_free_space(type, outss);
+  }
+}
+
 void BlueStore::set_cache_shards(unsigned num)
 {
   dout(10) << __func__ << " " << num << dendl;
index 1f7f49402084a98305b778e377ac39dabbcfdf1f..880fd4d7cea22074ea31a16daa6c9a88442bd41a 100644 (file)
@@ -3064,6 +3064,7 @@ public:
   std::string get_device_path(unsigned id);
 
   int dump_bluefs_sizes(std::ostream& out);
+  void trim_free_space(const std::string& type, std::ostream& outss);
 
 public:
   int statfs(struct store_statfs_t *buf,
index 32cc5ecf4edcc005437c2858e627034c8a386679..173450d79615b4b305eb05cbef5ef8886f1189dc 100644 (file)
@@ -285,9 +285,11 @@ int main(int argc, char **argv)
   string dest_file;
   string key, value;
   vector<string> allocs_name;
+  vector<string> bdev_type;
   string empty_sharding(1, '\0');
   string new_sharding = empty_sharding;
   string resharding_ctrl;
+  string really;
   int log_level = 30;
   bool fsck_deep = false;
   po::options_description po_options("Options");
@@ -309,6 +311,8 @@ int main(int argc, char **argv)
     ("key,k", po::value<string>(&key), "label metadata key name")
     ("value,v", po::value<string>(&value), "label metadata value")
     ("allocator", po::value<vector<string>>(&allocs_name), "allocator to inspect: 'block'/'bluefs-wal'/'bluefs-db'")
+    ("bdev-type", po::value<vector<string>>(&bdev_type), "bdev type to inspect: 'bdev-block'/'bdev-wal'/'bdev-db'")
+    ("really", po::value<string>(&really), "--yes-i-really-really-mean-it")
     ("sharding", po::value<string>(&new_sharding), "new sharding to apply")
     ("resharding-ctrl", po::value<string>(&resharding_ctrl), "gives control over resharding procedure details")
     ("op", po::value<string>(&action_aux),
@@ -340,7 +344,8 @@ int main(int argc, char **argv)
         "free-fragmentation, "
         "bluefs-stats, "
         "reshard, "
-        "show-sharding")
+        "show-sharding, "
+       "trim")
     ;
   po::options_description po_all("All options");
   po_all.add(po_options).add(po_positional);
@@ -572,6 +577,29 @@ int main(int argc, char **argv)
       exit(EXIT_FAILURE);
     }
   }
+  if (action == "trim") {
+    if (path.empty()) {
+      cerr << "must specify bluestore path" << std::endl;
+      exit(EXIT_FAILURE);
+    }
+    if (really.empty() || strcmp(really.c_str(), "--yes-i-really-really-mean-it") != 0) {
+      cerr << "Trimming a non healthy bluestore is a dangerous operation which could cause data loss, "
+           << "please run fsck and confirm with --yes-i-really-really-mean-it option"
+           << std::endl;
+      exit(EXIT_FAILURE);
+    }
+    for (auto type : bdev_type) {
+      if (!type.empty() &&
+          type != "bdev-block" &&
+          type != "bdev-db" &&
+          type != "bdev-wal") {
+        cerr << "unknown bdev type '" << type << "'" << std::endl;
+        exit(EXIT_FAILURE);
+      }
+    }
+    if (bdev_type.empty())
+      bdev_type = vector<string>{"bdev-block", "bdev-db", "bdev-wal"};
+  }
 
   if (action == "restore_cfb") {
 #ifndef CEPH_BLUESTORE_TOOL_RESTORE_ALLOCATION
@@ -1175,6 +1203,20 @@ int main(int argc, char **argv)
       exit(EXIT_FAILURE);
     }
     cout << sharding << std::endl;
+  } else if (action == "trim") {
+    BlueStore bluestore(cct.get(), path);
+    int r = bluestore.cold_open();
+    if (r < 0) {
+      cerr << "error from cold_open: " << cpp_strerror(r) << std::endl;
+      exit(EXIT_FAILURE);
+    }
+    for (auto type : bdev_type) {
+      cout << "trimming: " << type << std::endl;
+      ostringstream outss;
+      bluestore.trim_free_space(type, outss);
+      cout << "status: " << outss.str() << std::endl;
+    }
+    bluestore.cold_close();
   } else {
     cerr << "unrecognized action " << action << std::endl;
     return 1;