]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: Add error_code glue/infrastructure
authorAdam C. Emerson <aemerson@redhat.com>
Wed, 16 Aug 2017 19:53:51 +0000 (15:53 -0400)
committerAdam C. Emerson <aemerson@redhat.com>
Fri, 15 May 2020 14:55:10 +0000 (10:55 -0400)
Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
src/CMakeLists.txt
src/common/error_code.cc [new file with mode: 0644]
src/common/error_code.h [new file with mode: 0644]

index b77f77c9c6acf3d27185c92cfc2b7d3d772295cc..d7cb95b171fb90f9e088f17c0f40642d81a88ce8 100644 (file)
@@ -322,6 +322,7 @@ set(libcommon_files
   ceph_ver.c
   global/global_context.cc
   xxHash/xxhash.c
+  common/error_code.cc
   log/Log.cc
   mon/MonCap.cc
   mon/MonClient.cc
diff --git a/src/common/error_code.cc b/src/common/error_code.cc
new file mode 100644 (file)
index 0000000..c10f98a
--- /dev/null
@@ -0,0 +1,196 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2017 Red Hat, Inc. <contact@redhat.com>
+ *
+ * Author: Adam C. Emerson <aemerson@redhat.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version
+ * 2.1, as published by the Free Software Foundation.  See file
+ * COPYING.
+ */
+
+#include <exception>
+
+#include "common/error_code.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+
+using boost::system::error_category;
+using boost::system::error_condition;
+using boost::system::generic_category;
+using boost::system::system_category;
+
+namespace ceph {
+
+// A category for error conditions particular to Ceph
+
+class ceph_error_category : public converting_category {
+public:
+  ceph_error_category(){}
+  const char* name() const noexcept override;
+  using converting_category::message;
+  std::string message(int ev) const override;
+  const char* message(int ev, char*, std::size_t) const noexcept override;
+  using converting_category::equivalent;
+  bool equivalent(const boost::system::error_code& c,
+                 int ev) const noexcept override;
+  int from_code(int ev) const noexcept override;
+};
+
+const char* ceph_error_category::name() const noexcept {
+  return "ceph";
+}
+
+const char* ceph_error_category::message(int ev, char*,
+                                        std::size_t) const noexcept {
+  if (ev == 0)
+    return "No error";
+
+  switch (static_cast<errc>(ev)) {
+
+  case errc::not_in_map:
+    return "Map does not contain requested entry.";
+  case errc::does_not_exist:
+    return "Item does not exist";
+  case errc::failure:
+    return "An internal fault or inconsistency occurred";
+  case errc::exists:
+    return "Already exists";
+  case errc::limit_exceeded:
+    return "Attempt to use too much";
+  case errc::auth:
+    return "Authentication error";
+  case errc::conflict:
+    return "Conflict detected or precondition failed";
+  }
+
+  return "Unknown error.";
+}
+
+std::string ceph_error_category::message(int ev) const {
+  return message(ev, nullptr, 0);
+}
+
+bool ceph_error_category::equivalent(const boost::system::error_code& c,
+                                    int ev) const noexcept {
+  if (c.category() == system_category()) {
+    if (c.value() == boost::system::errc::no_such_file_or_directory) {
+      if (ev == static_cast<int>(errc::not_in_map) ||
+         ev == static_cast<int>(errc::does_not_exist)) {
+       // Blargh. A bunch of stuff returns ENOENT now, so just to be safe.
+       return true;
+      }
+    }
+    if (c.value() == boost::system::errc::io_error) {
+      if (ev == static_cast<int>(errc::failure)) {
+       return true;
+      }
+    }
+    if (c.value() == boost::system::errc::file_exists) {
+      if (ev == static_cast<int>(errc::exists)) {
+       return true;
+      }
+    }
+    if (c.value() == boost::system::errc::no_space_on_device ||
+       c.value() == boost::system::errc::invalid_argument) {
+      if (ev == static_cast<int>(errc::limit_exceeded)) {
+       return true;
+      }
+    }
+    if (c.value() == boost::system::errc::operation_not_permitted) {
+      if (ev == static_cast<int>(ceph::errc::conflict)) {
+       return true;
+      }
+    }
+  }
+  return false;
+}
+
+int ceph_error_category::from_code(int ev) const noexcept {
+  if (ev == 0)
+    return 0;
+
+  switch (static_cast<errc>(ev)) {
+  case errc::not_in_map:
+  case errc::does_not_exist:
+    // What we use now.
+    return -ENOENT;
+  case errc::failure:
+    return -EIO;
+  case errc::exists:
+    return -EEXIST;
+  case errc::limit_exceeded:
+    return -EIO;
+  case errc::auth:
+    return -EACCES;
+  case errc::conflict:
+    return -EINVAL;
+  }
+  return -EDOM;
+}
+
+const error_category& ceph_category() noexcept {
+  static const ceph_error_category c;
+  return c;
+}
+
+
+// This is part of the glue for hooking new code to old. Since
+// Context* and other things give us integer codes from errno, wrap
+// them in an error_code.
+boost::system::error_code to_error_code(int ret) noexcept
+{
+  if (ret == 0)
+    return {};
+  return { std::abs(ret), boost::system::system_category() };
+}
+
+// This is more complicated. For the case of categories defined
+// elsewhere, we have to convert everything here.
+int from_error_code(boost::system::error_code e) noexcept
+{
+  if (!e)
+    return 0;
+
+  auto c = dynamic_cast<const converting_category*>(&e.category());
+  // For categories we define
+  if (c)
+    return c->from_code(e.value());
+
+  // For categories matching values of errno
+  if (e.category() == boost::system::system_category() ||
+      e.category() == boost::system::generic_category() ||
+      // ASIO uses the system category for these and matches system
+      // error values.
+      e.category() == boost::asio::error::get_netdb_category() ||
+      e.category() == boost::asio::error::get_addrinfo_category())
+    return -e.value();
+
+  if (e.category() == boost::asio::error::get_misc_category()) {
+    // These values are specific to asio
+    switch (e.value()) {
+    case boost::asio::error::already_open:
+      return -EIO;
+    case boost::asio::error::eof:
+      return -EIO;
+    case boost::asio::error::not_found:
+      return -ENOENT;
+    case boost::asio::error::fd_set_failure:
+      return -EINVAL;
+    }
+  }
+  // Add any other categories we use here.
+
+  // Marcus likes this as a sentinel for 'Error code? What error code?'
+  return -EDOM;
+}
+}
+#pragma GCC diagnostic pop
+#pragma clang diagnostic pop
diff --git a/src/common/error_code.h b/src/common/error_code.h
new file mode 100644 (file)
index 0000000..8a9b9b0
--- /dev/null
@@ -0,0 +1,80 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2017 Red Hat, Inc. <contact@redhat.com>
+ *
+ * Author: Adam C. Emerson <aemerson@redhat.com>
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version
+ * 2.1, as published by the Free Software Foundation.  See file
+ * COPYING.
+ */
+
+#ifndef COMMON_CEPH_ERROR_CODE
+#define COMMON_CEPH_ERROR_CODE
+
+#include <netdb.h>
+
+#include <boost/system/error_code.hpp>
+#include <boost/asio.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+
+namespace ceph {
+
+// This is for error categories we define, so we can specify the
+// equivalent integral value at the point of definition.
+class converting_category : public boost::system::error_category {
+public:
+  virtual int from_code(int code) const noexcept = 0;
+};
+
+const boost::system::error_category& ceph_category() noexcept;
+
+enum class errc {
+  not_in_map = 1, // The requested item was not found in the map
+  does_not_exist, // Item does not exist
+  failure, // An internal fault or inconsistency
+  exists, // Already exists
+  limit_exceeded, // Attempting to use too much of something
+  auth, // May not be an auth failure. It could be that the
+       // preconditions to attempt auth failed.
+  conflict, // Conflict or precondition failure
+};
+}
+
+namespace boost::system {
+template<>
+struct is_error_condition_enum<::ceph::errc> {
+  static const bool value = true;
+};
+template<>
+struct is_error_code_enum<::ceph::errc> {
+  static const bool value = false;
+};
+}
+
+namespace ceph {
+//  explicit conversion:
+inline boost::system::error_code make_error_code(errc e) noexcept {
+  return { static_cast<int>(e), ceph_category() };
+}
+
+// implicit conversion:
+inline boost::system::error_condition make_error_condition(errc e) noexcept {
+  return { static_cast<int>(e), ceph_category() };
+}
+
+boost::system::error_code to_error_code(int ret) noexcept;
+int from_error_code(boost::system::error_code e) noexcept;
+}
+#pragma GCC diagnostic pop
+#pragma clang diagnostic pop
+
+#endif // COMMON_CEPH_ERROR_CODE