]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: block.db support
authorSage Weil <sage@redhat.com>
Thu, 10 Dec 2015 22:17:45 +0000 (17:17 -0500)
committerSage Weil <sage@redhat.com>
Fri, 1 Jan 2016 18:06:58 +0000 (13:06 -0500)
Support a mid- to fast device that will preferentially
store the rocksdb data (and wal, if block.wal is not
present).

Signed-off-by: Sage Weil <sage@redhat.com>
src/common/config_opts.h
src/kv/RocksDBStore.cc
src/os/bluestore/BlueFS.cc
src/os/bluestore/BlueFS.h
src/os/bluestore/BlueStore.cc
src/os/bluestore/BlueStore.h

index 36cbcdb1e500920fc3554a3813b2952bea31c92e..c686de938496867071acf0a7e21dee8c9bdc3ee3 100644 (file)
@@ -776,6 +776,7 @@ OPTION(kinetic_use_ssl, OPT_BOOL, false) // whether to secure kinetic traffic wi
 
 
 OPTION(rocksdb_separate_wal_dir, OPT_BOOL, false) // use $path.wal for wal
+OPTION(rocksdb_db_paths, OPT_STR, "")   // path,size( path,size)*
 OPTION(rocksdb_log_to_ceph_log, OPT_BOOL, true)  // log to ceph log
 // rocksdb options that will be used for keyvaluestore(if backend is rocksdb)
 OPTION(keyvaluestore_rocksdb_options, OPT_STR, "")
@@ -841,8 +842,7 @@ OPTION(bluefs_log_compact_min_ratio, OPT_FLOAT, 5.0)      // before we consider
 OPTION(bluefs_log_compact_min_size, OPT_U64, 16*1048576)  // before we consider
 
 OPTION(bluestore_bluefs, OPT_BOOL, false)
-OPTION(bluestore_bluefs_mirror, OPT_BOOL, false) // mirror to normal Env for debug
-OPTION(bluestore_bluefs_initial_offset, OPT_U64,  1024*1024)
+OPTION(bluestore_bluefs_env_mirror, OPT_BOOL, false) // mirror to normal Env for debug
 OPTION(bluestore_bluefs_initial_length, OPT_U64, 65536*1024)
 OPTION(bluestore_bluefs_min_ratio, OPT_FLOAT, .01)
 OPTION(bluestore_bluefs_min_free_ratio, OPT_FLOAT, .1)
@@ -850,6 +850,8 @@ OPTION(bluestore_bluefs_max_free_fs_main_ratio, OPT_FLOAT, .8)
 OPTION(bluestore_bluefs_min_gift_ratio, OPT_FLOAT, 1)
 OPTION(bluestore_block_path, OPT_STR, "")
 OPTION(bluestore_block_size, OPT_U64, 10 * 1024*1024*1024)  // 10gb for testing
+OPTION(bluestore_block_db_path, OPT_STR, "")
+OPTION(bluestore_block_db_size, OPT_U64, 64 * 1024*1024)  // 64MB for testing
 OPTION(bluestore_block_wal_path, OPT_STR, "")
 OPTION(bluestore_block_wal_size, OPT_U64, 128 * 1024*1024)  // 128MB for testing
 OPTION(bluestore_max_dir_size, OPT_U32, 1000000)
index dd604018c6ad688dccf22ad199ae2ea532b82bf7..9b99605b62e32ac3d4241049124bd7a57e81e026 100644 (file)
@@ -21,6 +21,7 @@
 using std::string;
 #include "common/perf_counters.h"
 #include "common/debug.h"
+#include "include/str_list.h"
 #include "include/str_map.h"
 #include "KeyValueDB.h"
 #include "RocksDBStore.h"
@@ -181,6 +182,28 @@ int RocksDBStore::do_open(ostream &out, bool create_if_missing)
   if (g_conf->rocksdb_separate_wal_dir) {
     opt.wal_dir = path + ".wal";
   }
+  if (g_conf->rocksdb_db_paths.length()) {
+    list<string> paths;
+    get_str_list(g_conf->rocksdb_db_paths, "; \t", paths);
+    for (auto& p : paths) {
+      size_t pos = p.find(',');
+      if (pos == std::string::npos) {
+       derr << __func__ << " invalid db path item " << p << " in "
+            << g_conf->rocksdb_db_paths << dendl;
+       return -EINVAL;
+      }
+      string path = p.substr(0, pos);
+      string size_str = p.substr(pos + 1);
+      uint64_t size = atoll(size_str.c_str());
+      if (!size) {
+       derr << __func__ << " invalid db path item " << p << " in "
+            << g_conf->rocksdb_db_paths << dendl;
+       return -EINVAL;
+      }
+      opt.db_paths.push_back(rocksdb::DbPath(path, size));
+      dout(10) << __func__ << " db_path " << path << " size " << size << dendl;
+    }
+  }
 
   if (g_conf->rocksdb_log_to_ceph_log) {
     opt.info_log.reset(new CephRocksdbLogger(g_ceph_context));
index f41efd89caf96e998a4319474ec9663daf93f629..97db917e713b26e30a8a2c09282674294e93bb65 100644 (file)
@@ -126,8 +126,7 @@ int BlueFS::mkfs(uuid_d osd_uuid)
   // init log
   FileRef log_file = new File;
   log_file->fnode.ino = 1;
-  if (bdev.size() >= 2)
-    log_file->fnode.prefer_bdev = 1;
+  log_file->fnode.prefer_bdev = bdev.size() - 1;
   _allocate(log_file->fnode.prefer_bdev,
            g_conf->bluefs_max_log_runway,
            &log_file->fnode.extents);
@@ -1118,20 +1117,38 @@ int BlueFS::open_for_write(
   } else {
     // overwrite existing file?
     file = q->second;
-    if (!overwrite) {
+    if (overwrite) {
       dout(20) << __func__ << " dir " << dirname << " (" << dir
               << ") file " << filename
-              << " already exists, overwriting" << dendl;
+              << " already exists, overwrite in place" << dendl;
     } else {
       dout(20) << __func__ << " dir " << dirname << " (" << dir
               << ") file " << filename
-              << " already exists, overwriting" << dendl;
+              << " already exists, truncate + overwrite" << dendl;
       file->fnode.size = 0;
     }
     file->fnode.mtime = ceph_clock_now(NULL);
     log_t.op_file_update(file->fnode);
   }
 
+  if (dirname.length() > 5) {
+    // the "db.slow" and "db.wal" directory names are hard-coded at
+    // match up with bluestore.  the slow device is always the second
+    // one (when a dedicated block.db device is present and used at
+    // bdev 0).  the wal device is always last.
+    if (strcmp(dirname.c_str() + dirname.length() - 5, ".slow") == 0) {
+      assert(bdev.size() > 1);
+      dout(20) << __func__ << " mapping " << dirname << "/" << filename
+              << " to bdev 1" << dendl;
+      file->fnode.prefer_bdev = 1;
+    } else if (strcmp(dirname.c_str() + dirname.length() - 4, ".wal") == 0) {
+      assert(bdev.size() > 1);
+      file->fnode.prefer_bdev = bdev.size() - 1;
+      dout(20) << __func__ << " mapping " << dirname << "/" << filename
+              << " to bdev " << (int)file->fnode.prefer_bdev << dendl;
+    }
+  }
+
   *h = new FileWriter(file, bdev.size());
   dout(10) << __func__ << " h " << *h << " on " << file->fnode << dendl;
   return 0;
index 9c6a971343dc1f1116c6735e2de612f38af67e34..7e62d74348545f53f559eb469a39e5fd4b334085 100644 (file)
@@ -162,6 +162,21 @@ private:
   FileWriter *log_writer;     ///< writer for the log
   bluefs_transaction_t log_t; ///< pending, unwritten log transaction
 
+  /*
+   * - there can be from 1 to 3 block devices.
+   *
+   * - the first device always has the superblock.
+   *
+   * - if there is a dedicated db device, it is the first device, and the
+   *   second device is shared with bluestore.  the first device will be
+   *   db/, and the second device will be db.slow/.
+   *
+   * - if there is no dedicated db device, then the first device is shared, and
+   *   maps to the db/ directory.
+   *
+   * - a wal device, if present, it always the last device.  it should be
+   *   used for any files in the db.wal/ directory.
+   */
   vector<BlockDevice*> bdev;                  ///< block devices we can use
   vector<IOContext*> ioc;                     ///< IOContexts for bdevs
   vector<interval_set<uint64_t> > block_all;  ///< extents in bdev we own
index 2d6a88dc6fa296705a0df757f82f6efa30de042d..d7c898a028ab50e9afcd92c4bd78be776cf315a7 100644 (file)
@@ -71,6 +71,9 @@ const string PREFIX_ALLOC = "B";  // block allocator
 // superblock (always the second block of the device).
 #define BDEV_LABEL_BLOCK_SIZE  4096
 
+// for bluefs, label (4k) + bluefs super (4k), means we start at 8k.
+#define BLUEFS_START  8192
+
 /*
  * object name key structure
  *
@@ -677,6 +680,7 @@ BlueStore::BlueStore(CephContext *cct, const string& path)
   : ObjectStore(path),
     cct(cct),
     bluefs(NULL),
+    bluefs_shared_bdev(0),
     db(NULL),
     fs(NULL),
     bdev(NULL),
@@ -836,36 +840,45 @@ int BlueStore::_read_bdev_label(string path, bluestore_bdev_label_t *label)
   return 0;
 }
 
-int BlueStore::_open_bdev(bool create)
+int BlueStore::_check_or_set_bdev_label(
+  string path, uint64_t size, string desc, bool create)
 {
   bluestore_bdev_label_t label;
-  assert(bdev == NULL);
-  bdev = new BlockDevice(aio_cb, static_cast<void*>(this));
-  string p = path + "/block";
-  int r = bdev->open(p);
-  if (r < 0)
-    goto fail;
-
   if (create) {
     label.osd_uuid = fsid;
-    label.size = bdev->get_size();
+    label.size = size;
     label.btime = ceph_clock_now(NULL);
-    label.description = "main";
-    r = _write_bdev_label(p, label);
+    label.description = desc;
+    int r = _write_bdev_label(path, label);
     if (r < 0)
-      goto fail;
+      return r;
   } else {
-    r = _read_bdev_label(p, &label);
+    int r = _read_bdev_label(path, &label);
     if (r < 0)
-      goto fail;
+      return r;
     if (label.osd_uuid != fsid) {
-      derr << __func__ << " bdev " << p << " fsid " << label.osd_uuid
+      derr << __func__ << " bdev " << path << " fsid " << label.osd_uuid
           << " does not match our fsid " << fsid << dendl;
-      r = -EIO;
-      goto fail;
+      return -EIO;
     }
   }
   return 0;
+}
+
+int BlueStore::_open_bdev(bool create)
+{
+  bluestore_bdev_label_t label;
+  assert(bdev == NULL);
+  bdev = new BlockDevice(aio_cb, static_cast<void*>(this));
+  string p = path + "/block";
+  int r = bdev->open(p);
+  if (r < 0)
+    goto fail;
+
+  r = _check_or_set_bdev_label(p, bdev->get_size(), "main", create);
+  if (r < 0)
+    goto fail;
+  return 0;
 
  fail:
   delete bdev;
@@ -1031,42 +1044,68 @@ int BlueStore::_open_db(bool create)
       return -EINVAL;
     }
     bluefs = new BlueFS;
+
     char bfn[PATH_MAX];
+    struct stat st;
+    int id = 0;
+
+    snprintf(bfn, sizeof(bfn), "%s/block.db", path.c_str());
+    if (::stat(bfn, &st) == 0) {
+      bluefs->add_block_device(id, bfn);
+      int r = _check_or_set_bdev_label(bfn, bluefs->get_block_device_size(id),
+                                      "bluefs db", create);
+      if (r < 0)
+       return r;
+      if (create) {
+       bluefs->add_block_extent(
+         id, BLUEFS_START,
+         bluefs->get_block_device_size(id) - BLUEFS_START);
+      }
+      ++id;
+    }
+
     snprintf(bfn, sizeof(bfn), "%s/block", path.c_str());
-    bluefs->add_block_device(0, bfn);
+    bluefs->add_block_device(id, bfn);
     if (create) {
-      bluefs->add_block_extent(0, g_conf->bluestore_bluefs_initial_offset,
+      // note: we might waste a 4k block here if block.db is used, but it's
+      // simpler.
+      bluefs->add_block_extent(id, BLUEFS_START,
                               g_conf->bluestore_bluefs_initial_length);
     }
+    bluefs_shared_bdev = id;
+    ++id;
+    if (id == 2) {
+      // we have both block.db and block; tell rocksdb!
+      // note: the second (last) size value doesn't really matter
+      char db_paths[PATH_MAX*3];
+      snprintf(
+       db_paths, sizeof(db_paths), "%s/db,%lld %s/db.slow,%lld",
+       path.c_str(),
+       (unsigned long long)bluefs->get_block_device_size(0) * 95 / 100,
+       path.c_str(),
+       (unsigned long long)bluefs->get_block_device_size(1) * 95 / 100);
+      g_conf->set_val("rocksdb_db_paths", db_paths, false, false);
+      dout(10) << __func__ << " set rocksdb_db_paths to "
+              << g_conf->rocksdb_db_paths << dendl;
+    }
+
     snprintf(bfn, sizeof(bfn), "%s/block.wal", path.c_str());
-    struct stat st;
     if (::stat(bfn, &st) == 0) {
-      bluefs->add_block_device(1, bfn);
-      // label in first 4k
-      bluestore_bdev_label_t label;
+      bluefs->add_block_device(id, bfn);
+      int r = _check_or_set_bdev_label(bfn, bluefs->get_block_device_size(id),
+                                      "bluefs wal", create);
+      if (r < 0)
+       return r;
       if (create) {
-       label.osd_uuid = fsid;
-       label.size = bluefs->get_block_device_size(1);
-       label.btime = ceph_clock_now(NULL);
-       label.description = "bluefs wal";
-       int r = _write_bdev_label(bfn, label);
-       if (r < 0)
-         return r;
-       // reset belongs to bluefs
        bluefs->add_block_extent(
-         1, BDEV_LABEL_BLOCK_SIZE,
-         bluefs->get_block_device_size(1) - BDEV_LABEL_BLOCK_SIZE);
-      } else {
-       int r = _read_bdev_label(bfn, &label);
-       if (r < 0)
-         return r;
-       if (label.osd_uuid != fsid) {
-         derr << __func__ << " bdev " << bfn << " fsid " << label.osd_uuid
-              << " does not match our fsid " << fsid << dendl;
-         return -EIO;
-       }
+         id, BDEV_LABEL_BLOCK_SIZE,
+         bluefs->get_block_device_size(id) - BDEV_LABEL_BLOCK_SIZE);
       }
+      g_conf->set_val("rocksdb_separate_wal_dir", "true");
+    } else {
+      g_conf->set_val("rocksdb_separate_wal_dir", "false");
     }
+
     if (create) {
       bluefs->mkfs(fsid);
     }
@@ -1076,12 +1115,14 @@ int BlueStore::_open_db(bool create)
       delete bluefs;
       return r;
     }
-    if (g_conf->bluestore_bluefs_mirror) {
+    if (g_conf->bluestore_bluefs_env_mirror) {
       rocksdb::Env *a = new BlueRocksEnv(bluefs);
       unique_ptr<rocksdb::Directory> dir;
       rocksdb::Env *b = rocksdb::Env::Default();
       if (create) {
-       string cmd = "rm -r " + path + "/db";
+       string cmd = "rm -rf " + path + "/db " +
+         path + "/db.slow" +
+         path + "/db.wal";
        int r = system(cmd.c_str());
        (void)r;
       }
@@ -1095,6 +1136,10 @@ int BlueStore::_open_db(bool create)
 
     if (create) {
       env->CreateDir(fn);
+      if (g_conf->rocksdb_separate_wal_dir)
+       env->CreateDir(string(fn) + ".wal");
+      if (g_conf->rocksdb_db_paths.length())
+       env->CreateDir(string(fn) + ".slow");
     }
   } else if (create) {
     int r = ::mkdir(fn, 0755);
@@ -1185,7 +1230,7 @@ int BlueStore::_reconcile_bluefs_freespace()
 {
   dout(10) << __func__ << dendl;
   interval_set<uint64_t> bset;
-  int r = bluefs->get_block_extents(0, &bset);
+  int r = bluefs->get_block_extents(bluefs_shared_bdev, &bset);
   assert(r == 0);
   if (bset == bluefs_extents) {
     dout(10) << __func__ << " we agree bluefs has " << bset << dendl;
@@ -1213,7 +1258,7 @@ int BlueStore::_reconcile_bluefs_freespace()
     for (interval_set<uint64_t>::iterator p = super_extra.begin();
         p != super_extra.end();
         ++p) {
-      bluefs->add_block_extent(0, p.get_start(), p.get_len());
+      bluefs->add_block_extent(bluefs_shared_bdev, p.get_start(), p.get_len());
     }
   }
 
@@ -1226,8 +1271,8 @@ int BlueStore::_balance_bluefs_freespace(vector<extent_t> *extents)
   assert(bluefs);
 
   // fixme: look at primary bdev only for now
-  uint64_t bluefs_total = bluefs->get_total(0);
-  uint64_t bluefs_free = bluefs->get_free(0);
+  uint64_t bluefs_total = bluefs->get_total(bluefs_shared_bdev);
+  uint64_t bluefs_free = bluefs->get_free(bluefs_shared_bdev);
   float bluefs_free_ratio = (float)bluefs_free / (float)bluefs_total;
 
   uint64_t my_free = alloc->get_free();
@@ -1307,7 +1352,7 @@ void BlueStore::_commit_bluefs_freespace(
 {
   dout(10) << __func__ << dendl;
   for (auto& p : bluefs_gift_extents) {
-    bluefs->add_block_extent(0, p.offset, p.length);
+    bluefs->add_block_extent(bluefs_shared_bdev, p.offset, p.length);
   }
 }
 
@@ -1335,6 +1380,43 @@ int BlueStore::_open_collections(int *errors)
   return 0;
 }
 
+int BlueStore::_setup_block_symlink_or_file(
+  string name,
+  string path,
+  uint64_t size)
+{
+  dout(20) << __func__ << " name " << name << " path " << path
+          << " size " << size << dendl;
+  if (path.length()) {
+    int r = ::symlinkat(path.c_str(), path_fd, name.c_str());
+    if (r < 0) {
+      r = -errno;
+      derr << __func__ << " failed to create " << name << " symlink to "
+          << path << ": " << cpp_strerror(r) << dendl;
+      return r;
+    }
+  } else if (size) {
+    struct stat st;
+    int r = ::fstatat(path_fd, name.c_str(), &st, 0);
+    if (r < 0)
+      r = -errno;
+    if (r == -ENOENT) {
+      int fd = ::openat(path_fd, name.c_str(), O_CREAT|O_RDWR, 0644);
+      if (fd < 0) {
+       int r = -errno;
+       derr << __func__ << " faile to create " << name << " file: "
+            << cpp_strerror(r) << dendl;
+       return r;
+      }
+      int r = ::ftruncate(fd, size);
+      assert(r == 0);
+      dout(1) << __func__ << " created " << name << " file with size "
+             << pretty_si_t(size) << "B" << dendl;
+    }
+  }
+  return 0;
+}
+
 int BlueStore::mkfs()
 {
   dout(1) << __func__ << " path " << path << dendl;
@@ -1374,65 +1456,18 @@ int BlueStore::mkfs()
     goto out_close_fsid;
   }
 
-  // block symlink/file
-  if (g_conf->bluestore_block_path.length()) {
-    int r = ::symlinkat(g_conf->bluestore_block_path.c_str(), path_fd, "block");
-    if (r < 0) {
-      r = -errno;
-      derr << __func__ << " failed to create block symlink to "
-          << g_conf->bluestore_block_path << ": " << cpp_strerror(r) << dendl;
-      goto out_close_fsid;
-    }
-  } else if (g_conf->bluestore_block_size) {
-    struct stat st;
-    int r = ::fstatat(path_fd, "block", &st, 0);
-    if (r < 0)
-      r = -errno;
-    if (r == -ENOENT) {
-      int fd = ::openat(path_fd, "block", O_CREAT|O_RDWR, 0644);
-      if (fd < 0) {
-       int r = -errno;
-       derr << __func__ << " faile to create block file: " << cpp_strerror(r)
-            << dendl;
-       goto out_close_fsid;
-      }
-      int r = ::ftruncate(fd, g_conf->bluestore_block_size);
-      assert(r == 0);
-      dout(1) << __func__ << " created block file with size "
-             << pretty_si_t(g_conf->bluestore_block_size) << "B" << dendl;
-    }
-  }
-
-  // block.wal symlink/file
-  if (g_conf->bluestore_block_wal_path.length()) {
-    int r = ::symlinkat(g_conf->bluestore_block_wal_path.c_str(), path_fd,
-                       "block.wal");
-    if (r < 0) {
-      r = -errno;
-      derr << __func__ << " failed to create block.wal symlink to "
-          << g_conf->bluestore_block_wal_path
-          << ": " << cpp_strerror(r) << dendl;
-      goto out_close_fsid;
-    }
-  } else if (g_conf->bluestore_block_wal_size) {
-    struct stat st;
-    int r = ::fstatat(path_fd, "block.wal", &st, 0);
-    if (r < 0)
-      r = -errno;
-    if (r == -ENOENT) {
-      int fd = ::openat(path_fd, "block.wal", O_CREAT|O_RDWR, 0644);
-      if (fd < 0) {
-       int r = -errno;
-       derr << __func__ << " faile to create block.wal file: "
-            << cpp_strerror(r) << dendl;
-       goto out_close_fsid;
-      }
-      int r = ::ftruncate(fd, g_conf->bluestore_block_wal_size);
-      assert(r == 0);
-      dout(1) << __func__ << " created block.wal file with size "
-             << pretty_si_t(g_conf->bluestore_block_wal_size) << "B" << dendl;
-    }
-  }
+  r = _setup_block_symlink_or_file("block", g_conf->bluestore_block_path,
+                                  g_conf->bluestore_block_size);
+  if (r < 0)
+    goto out_close_fsid;
+  r = _setup_block_symlink_or_file("block.wal", g_conf->bluestore_block_wal_path,
+                                  g_conf->bluestore_block_wal_size);
+  if (r < 0)
+    goto out_close_fsid;
+  r = _setup_block_symlink_or_file("block.db", g_conf->bluestore_block_db_path,
+                                  g_conf->bluestore_block_db_size);
+  if (r < 0)
+    goto out_close_fsid;
 
   r = _open_bdev(true);
   if (r < 0)
@@ -1452,12 +1487,10 @@ int BlueStore::mkfs()
     KeyValueDB::Transaction t = db->get_transaction();
     uint64_t reserved = 0;
     if (g_conf->bluestore_bluefs) {
-      reserved = g_conf->bluestore_bluefs_initial_offset +
-       g_conf->bluestore_bluefs_initial_length;
+      reserved = BLUEFS_START + g_conf->bluestore_bluefs_initial_length;
       dout(20) << __func__ << " reserved first " << reserved
               << " bytes for bluefs" << dendl;
-
-      bluefs_extents.insert(g_conf->bluestore_bluefs_initial_offset,
+      bluefs_extents.insert(BLUEFS_START,
                            g_conf->bluestore_bluefs_initial_length);
       bufferlist bl;
       ::encode(bluefs_extents, bl);
@@ -1641,7 +1674,7 @@ int BlueStore::fsck()
     goto out_alloc;
 
   if (bluefs) {
-    used_blocks.insert(0, g_conf->bluestore_bluefs_initial_offset); // fixme
+    used_blocks.insert(0, BLUEFS_START);
     used_blocks.insert(bluefs_extents);
     r = bluefs->fsck();
     if (r < 0)
index 3d62e98bda9cf6c69f93809adde7a16443d412ef..fe8dafbbbf512e41220780d116087e1622015fc2 100644 (file)
@@ -391,6 +391,7 @@ public:
 private:
   CephContext *cct;
   BlueFS *bluefs;
+  unsigned bluefs_shared_bdev;  ///< which bluefs bdev we are sharing
   KeyValueDB *db;
   FS *fs;
   BlockDevice *bdev;
@@ -456,8 +457,12 @@ private:
   int _open_collections(int *errors=0);
   void _close_collections();
 
+  int _setup_block_symlink_or_file(string name, string path, uint64_t size);
+
   int _write_bdev_label(string path, bluestore_bdev_label_t label);
   static int _read_bdev_label(string path, bluestore_bdev_label_t *label);
+  int _check_or_set_bdev_label(string path, uint64_t size, string desc,
+                              bool create);
 
   int _open_super_meta();