]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
HashIndex: randomize split threshold by a configurable amount 19906/head
authorJosh Durgin <jdurgin@redhat.com>
Sat, 4 Jun 2016 01:46:15 +0000 (18:46 -0700)
committerJosh Durgin <jdurgin@redhat.com>
Thu, 11 Jan 2018 00:37:42 +0000 (16:37 -0800)
Store a random value up to the filestore_split_rand_factor for each
collection when it is created or apply-layout-settings is run. This
should help distribute the load of splitting directories across a
longer period of time.

Fixes: http://tracker.ceph.com/issues/15835
Signed-off-by: Josh Durgin <jdurgin@redhat.com>
(cherry picked from commit 78d0b278a6853a45eda9aa4c78aa0233e07c1299)

Conflicts:
src/os/filestore/IndexManager.cc (g_conf instead of cct)

doc/rados/configuration/filestore-config-ref.rst
src/ceph_osd.cc
src/common/config_opts.h
src/os/filestore/CollectionIndex.h
src/os/filestore/HashIndex.cc
src/os/filestore/HashIndex.h
src/os/filestore/IndexManager.cc

index 94953c057f07c84027446cfd5d2c198f761be081..b67a59e286ef69ca5b94d7d1e2f5ebc69b2e8383 100644 (file)
@@ -257,7 +257,7 @@ Misc
 
 ``filestore split multiple``
 
-:Description:  ``filestore_split_multiple * abs(filestore_merge_threshold) * 16`` 
+:Description:  ``(filestore_split_multiple * abs(filestore_merge_threshold) + (rand() % filestore_split_rand_factor)) * 16``
                is the maximum number of files in a subdirectory before 
                splitting into child directories.
 
@@ -266,6 +266,19 @@ Misc
 :Default: ``2``
 
 
+``filestore split rand factor``
+
+:Description:  A random factor added to the split threshold to avoid
+               too many filestore splits occurring at once. See
+               ``filestore split multiple`` for details.
+               This can only be changed for an existing osd offline,
+               via ceph-objectstore-tool's apply-layout-settings command.
+
+:Type: Unsigned 32-bit Integer
+:Required: No
+:Default: ``20``
+
+
 ``filestore update to``
 
 :Description: Limits filestore auto upgrade to specified version.
index 70377fe53e0e7cdafc587623771640f684fd69fe..628470dc1b99c4e625174758bc19c603238728c0 100644 (file)
@@ -578,6 +578,8 @@ flushjournal_out:
   if (preload_erasure_code() < 0)
     return -1;
 
+  srand(time(NULL) + getpid());
+
   osd = new OSD(g_ceph_context,
                 store,
                 whoami,
index 062675d08ffc7242d5ed822209e5ae973d1e4e4f..86ffbf1aa2c7a895eba4dd1bef9ffac2a5bb8b30 100644 (file)
@@ -1123,6 +1123,7 @@ OPTION(filestore_commit_timeout, OPT_FLOAT, 600)
 OPTION(filestore_fiemap_threshold, OPT_INT, 4096)
 OPTION(filestore_merge_threshold, OPT_INT, 10)
 OPTION(filestore_split_multiple, OPT_INT, 2)
+OPTION(filestore_split_rand_factor, OPT_U32, 20) // randomize the split threshold by adding 16 * [0, rand_factor)
 OPTION(filestore_update_to, OPT_INT, 1000)
 OPTION(filestore_blackhole, OPT_BOOL, false)     // drop any new transactions on the floor
 OPTION(filestore_fd_cache_size, OPT_INT, 128)    // FD lru size
index cbdc5d6afdac1baed67b129c28c2bafbe0b1bddf..cc96755c1a9917556e473b33f1fd64db14985298 100644 (file)
@@ -192,6 +192,9 @@ protected:
 
   virtual int apply_layout_settings() { assert(0); return 0; }
 
+  /// Read index-wide settings (should be called after construction)
+  virtual int read_settings() { return 0; }
+
   /// Virtual destructor
   virtual ~CollectionIndex() {}
 };
index fa5622c31391386673a8bd1006049a773bb3a715..2263142e9f10ae5f799a9075dcb30a14a449a73d 100644 (file)
@@ -24,6 +24,7 @@
 #define dout_subsys ceph_subsys_filestore
 
 const string HashIndex::SUBDIR_ATTR = "contents";
+const string HashIndex::SETTINGS_ATTR = "settings";
 const string HashIndex::IN_PROGRESS_OP_TAG = "in_progress_op";
 
 /// hex digit to integer value
@@ -357,14 +358,50 @@ int HashIndex::split_dirs(const vector<string> &path) {
 int HashIndex::apply_layout_settings() {
   vector<string> path;
   dout(10) << __func__ << " split multiple = " << split_multiplier
-          << " merge threshold = " << merge_threshold << dendl;
+          << " merge threshold = " << merge_threshold
+          << " split rand factor = " << g_conf->filestore_split_rand_factor
+          << dendl;
+  int r = write_settings();
+  if (r < 0)
+    return r;
   return split_dirs(path);
 }
 
 int HashIndex::_init() {
   subdir_info_s info;
   vector<string> path;
-  return set_info(path, info);
+  int r = set_info(path, info);
+  if (r < 0)
+    return r;
+  return write_settings();
+}
+
+int HashIndex::write_settings() {
+  if (g_conf->filestore_split_rand_factor > 0) {
+    settings.split_rand_factor = rand() % g_conf->filestore_split_rand_factor;
+  } else {
+    settings.split_rand_factor = 0;
+  }
+  vector<string> path;
+  bufferlist bl;
+  settings.encode(bl);
+  return add_attr_path(path, SETTINGS_ATTR, bl);
+}
+
+int HashIndex::read_settings() {
+  vector<string> path;
+  bufferlist bl;
+  int r = get_attr_path(path, SETTINGS_ATTR, bl);
+  if (r == -ENODATA)
+    return 0;
+  if (r < 0) {
+    derr << __func__ << " error reading settings: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+  bufferlist::iterator it = bl.begin();
+  settings.decode(it);
+  dout(20) << __func__ << " split_rand_factor = " << settings.split_rand_factor << dendl;
+  return 0;
 }
 
 /* LFNIndex virtual method implementations */
@@ -496,7 +533,7 @@ int HashIndex::pre_split_folder(uint32_t pg_num, uint64_t expected_num_objs)
 
   // Calculate the number of leaf folders (which actually store files)
   // need to be created
-  const uint64_t objs_per_folder = (uint64_t)(abs(merge_threshold)) * (uint64_t)split_multiplier * 16;
+  const uint64_t objs_per_folder = ((uint64_t)(abs(merge_threshold)) * (uint64_t)split_multiplier + settings.split_rand_factor) * 16;
   uint64_t leavies = expected_num_objs / objs_per_folder ;
   // No need to split
   if (leavies == 0 || expected_num_objs == objs_per_folder)
@@ -705,7 +742,7 @@ bool HashIndex::must_merge(const subdir_info_s &info) {
 
 bool HashIndex::must_split(const subdir_info_s &info) {
   return (info.hash_level < (unsigned)MAX_HASH_LEVEL &&
-         info.objs > ((unsigned)(abs(merge_threshold)) * 16 * split_multiplier));
+         info.objs > ((unsigned)(abs(merge_threshold) * split_multiplier + settings.split_rand_factor) * 16));
 
 }
 
index 73150c7cba63af6349c5d70d0020533af33d3c79..ba6383e3146382a205d8b6d5a41ff80845798944 100644 (file)
@@ -43,14 +43,17 @@ extern string reverse_hexdigit_bits_string(string l);
  * ex: ghobject_t("object", CEPH_NO_SNAP, 0xA4CEE0D2)
  * would be located in (root)/2/D/0/
  *
- * Subdirectories are created when the number of objects in a directory
- * exceed (abs(merge_threshhold)) * 16 * split_multiplier.  The number of objects in a directory
- * is encoded as subdir_info_s in an xattr on the directory.
+ * Subdirectories are created when the number of objects in a
+ * directory exceed 16 * (abs(merge_threshhold)) * split_multiplier +
+ * split_rand_factor). The number of objects in a directory is encoded
+ * as subdir_info_s in an xattr on the directory.
  */
 class HashIndex : public LFNIndex {
 private:
   /// Attribute name for storing subdir info @see subdir_info_s
   static const string SUBDIR_ATTR;
+  /// Attribute name for storing index-wide settings
+  static const string SETTINGS_ATTR;
   /// Attribute name for storing in progress op tag
   static const string IN_PROGRESS_OP_TAG;
   /// Size (bits) in object hash
@@ -61,8 +64,12 @@ private:
   /**
    * Merges occur when the number of object drops below
    * merge_threshold and splits occur when the number of objects
-   * exceeds 16 * abs(merge_threshold) * split_multiplier.
-   * Please note if merge_threshold is less than zero, it will never do merging
+   * exceeds:
+   *
+   *   16 * (abs(merge_threshold) * split_multiplier + split_rand_factor)
+   *
+   * Please note if merge_threshold is less than zero, it will never
+   * do merging
    */
   int merge_threshold;
   int split_multiplier;
@@ -95,6 +102,23 @@ private:
     }
   };
 
+  struct settings_s {
+    uint32_t split_rand_factor; ///< random factor added to split threshold (only on root of collection)
+    settings_s() : split_rand_factor(0) {}
+    void encode(bufferlist &bl) const
+    {
+      __u8 v = 1;
+      ::encode(v, bl);
+      ::encode(split_rand_factor, bl);
+    }
+    void decode(bufferlist::iterator &bl)
+    {
+      __u8 v;
+      ::decode(v, bl);
+      ::decode(split_rand_factor, bl);
+    }
+  } settings;
+
   /// Encodes in progress split or merge
   struct InProgressOp {
     static const int SPLIT = 0;
@@ -142,7 +166,10 @@ public:
     double retry_probability=0) ///< [in] retry probability
     : LFNIndex(collection, base_path, index_version, retry_probability),
       merge_threshold(merge_at),
-      split_multiplier(split_multiple) {}
+      split_multiplier(split_multiple)
+  {}
+
+  int read_settings() override;
 
   /// @see CollectionIndex
   uint32_t collection_version() { return index_version; }
@@ -438,6 +465,8 @@ private:
 
   /// split each dir below the given path
   int split_dirs(const vector<string> &path);
+
+  int write_settings();
 };
 
 #endif
index 078550de78de1eab111c57b6ed725f79a07163dc..b117e63704c0ea7e290ab322cc4b54a155f704fc 100644 (file)
@@ -82,7 +82,10 @@ int IndexManager::init_index(coll_t c, const char *path, uint32_t version) {
                  g_conf->filestore_split_multiple,
                  version,
                  g_conf->filestore_index_retry_probability);
-  return index.init();
+  r = index.init();
+  if (r < 0)
+    return r;
+  return index.read_settings();
 }
 
 int IndexManager::build_index(coll_t c, const char *path, CollectionIndex **index) {
@@ -102,7 +105,7 @@ int IndexManager::build_index(coll_t c, const char *path, CollectionIndex **inde
       // Must be a HashIndex
       *index = new HashIndex(c, path, g_conf->filestore_merge_threshold,
                                   g_conf->filestore_split_multiple, version);
-      return 0;
+      return (*index)->read_settings();
     }
     default: assert(0);
     }
@@ -113,7 +116,7 @@ int IndexManager::build_index(coll_t c, const char *path, CollectionIndex **inde
                                 g_conf->filestore_split_multiple,
                                 CollectionIndex::HOBJECT_WITH_POOL,
                                 g_conf->filestore_index_retry_probability);
-    return 0;
+    return (*index)->read_settings();
   }
 }