diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/ClassHandler.cc | 2 | ||||
-rw-r--r-- | src/common/DoutStreambuf.cc | 628 | ||||
-rw-r--r-- | src/common/DoutStreambuf.h | 106 | ||||
-rw-r--r-- | src/common/Finisher.cc | 2 | ||||
-rw-r--r-- | src/common/LogClient.cc | 87 | ||||
-rw-r--r-- | src/common/LogClient.h | 110 | ||||
-rw-r--r-- | src/common/LogEntry.h | 144 | ||||
-rw-r--r-- | src/common/Thread.h | 12 | ||||
-rw-r--r-- | src/common/Timer.cc | 2 | ||||
-rw-r--r-- | src/common/WorkQueue.cc | 2 | ||||
-rw-r--r-- | src/common/common_init.cc | 7 | ||||
-rw-r--r-- | src/common/debug.cc | 224 | ||||
-rw-r--r-- | src/common/debug.h | 116 | ||||
-rw-r--r-- | src/common/likely.h | 24 |
14 files changed, 1156 insertions, 310 deletions
diff --git a/src/common/ClassHandler.cc b/src/common/ClassHandler.cc index a2a13075bf3..405ab7388e4 100644 --- a/src/common/ClassHandler.cc +++ b/src/common/ClassHandler.cc @@ -14,7 +14,7 @@ #define DOUT_SUBSYS osd #undef dout_prefix -#define dout_prefix *_dout << dbeginl +#define dout_prefix *_dout static ClassHandler::ClassData null_cls_data; diff --git a/src/common/DoutStreambuf.cc b/src/common/DoutStreambuf.cc new file mode 100644 index 00000000000..4279e4fbebd --- /dev/null +++ b/src/common/DoutStreambuf.cc @@ -0,0 +1,628 @@ +// -*- 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) 2010 Dreamhost + * + * 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 "config.h" +#include "common/DoutStreambuf.h" +#include "common/errno.h" +#include "common/Mutex.h" + +#include <values.h> +#include <assert.h> +#include <errno.h> +#include <fstream> +#include <iostream> +#include <memory> +#include <sstream> +#include <streambuf> +#include <string.h> +#include <syslog.h> + +///////////////////////////// Globals ///////////////////////////// +// TODO: get rid of this lock using thread-local storage +extern Mutex _dout_lock; + +//////////////////////// Helper functions ////////////////////////// +// Try a 0-byte write to a file descriptor to see if it open. +static bool fd_is_open(int fd) +{ + char buf; + ssize_t res = TEMP_FAILURE_RETRY(write(fd, &buf, 0)); + return (res == 0); +} + +static bool empty(const char *str) +{ + if (!str) + return true; + if (!str[0]) + return true; + return false; +} + +static string cpp_str(const char *str) +{ + if (!str) + return "(NULL)"; + if (str[0] == '\0') + return "(empty)"; + return str; +} + +static std::string normalize_relative(const char *from) +{ + if (from[0] == '/') + return string(from); + + char c[512]; + char *cwd = getcwd(c, sizeof(c)); + ostringstream oss; + oss << cwd << "/" << from; + return oss.str(); +} + +/* Complain about errors even without a logfile */ +static void primitive_log(const std::string &str) +{ + std::cerr << str; + std::cerr.flush(); + syslog(LOG_USER | LOG_NOTICE, "%s", str.c_str()); +} + +static inline bool prio_is_visible_on_stderr(int prio) +{ + return prio <= 5; +} + +static inline int dout_prio_to_syslog_prio(int prio) +{ + if (prio <= 3) + return LOG_CRIT; + if (prio <= 5) + return LOG_ERR; + if (prio <= 15) + return LOG_WARNING; + if (prio <= 30) + return LOG_NOTICE; + if (prio <= 40) + return LOG_INFO; + return LOG_DEBUG; +} + +static int safe_write(int fd, const char *buf, signed int len) +{ + int res; + + assert(len != 0); + while (1) { + res = write(fd, buf, len); + if (res < 0) { + int err = errno; + if (err != EINTR) { + ostringstream oss; + oss << __func__ << ": failed to write to fd " << fd << ": " + << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return err; + } + } + len -= res; + buf += res; + if (len <= 0) + return 0; + } +} + +static std::string get_basename(const std::string &filename) +{ + size_t last_slash = filename.find_last_of("/"); + if (last_slash == std::string::npos) + return filename; + return filename.substr(last_slash + 1); +} + +static std::string get_dirname(const std::string &filename) +{ + size_t last_slash = filename.find_last_of("/"); + if (last_slash == std::string::npos) + return "."; + if (last_slash == 0) + return filename; + return filename.substr(0, last_slash); +} + +static int create_symlink(string oldpath, const string &newpath) +{ + // Create relative symlink if the files are in the same directory + if (get_dirname(oldpath) == get_dirname(newpath)) { + oldpath = string("./") + get_basename(oldpath); + } + + while (1) { + if (::symlink(oldpath.c_str(), newpath.c_str()) == 0) + return 0; + int err = errno; + if (err == EEXIST) { + // Handle EEXIST + if (::unlink(newpath.c_str())) { + err = errno; + ostringstream oss; + oss << __func__ << ": failed to remove '" << newpath << "': " + << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return err; + } + } + else { + // Other errors + ostringstream oss; + oss << __func__ << ": failed to symlink(oldpath='" << oldpath + << "', newpath='" << newpath << "'): " << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return err; + } + } +} + +///////////////////////////// DoutStreambuf ///////////////////////////// +template <typename charT, typename traits> +DoutStreambuf<charT, traits>::DoutStreambuf() + : flags(0), ofd(-1) +{ + // Initialize get pointer to zero so that underflow is called on the first read. + this->setg(0, 0, 0); + + // Initialize output_buffer + _clear_output_buffer(); +} + +// This function is called when the output buffer is filled. +// In this function, the buffer should be written to wherever it should +// be written to (in this case, the streambuf object that this is controlling). +template <typename charT, typename traits> +typename DoutStreambuf<charT, traits>::int_type +DoutStreambuf<charT, traits>::overflow(DoutStreambuf<charT, traits>::int_type c) +{ + { + // zero-terminate the buffer + charT* end_ptr = this->pptr(); + *end_ptr++ = '\0'; + *end_ptr++ = '\0'; +// char buf[1000]; +// hex2str(obuf, end_ptr - obuf, buf, sizeof(buf)); +// printf("overflow buffer: '%s'\n", buf); + } + + // Loop over all lines in the buffer. + int prio = 100; + charT* start = obuf; + while (true) { + char* end = strchrnul(start, '\n'); + if (start == end) { + if (*start == '\0') + break; + // skip zero-length lines + ++start; + continue; + } + if (*start == '\1') { + // Decode some control characters + ++start; + unsigned char tmp = *((unsigned char*)start); + prio = tmp - 11; + ++start; + } + *end = '\n'; + char next = *(end+1); + *(end+1) = '\0'; + + // Now 'start' points to a NULL-terminated string, which we want to + // output with priority 'prio' + int len = strlen(start); + if (flags & DOUTSB_FLAG_SYSLOG) { + //printf("syslogging: '%s' len=%d\n", start, len); + syslog(LOG_USER | dout_prio_to_syslog_prio(prio), "%s", start); + } + if (flags & DOUTSB_FLAG_STDOUT) { + // Just write directly out to the stdout fileno. There's no point in + // using something like fputs to write to a temporary buffer, + // because we would just have to flush that temporary buffer + // immediately. + if (safe_write(STDOUT_FILENO, start, len)) + flags &= ~DOUTSB_FLAG_STDOUT; + } + if (flags & DOUTSB_FLAG_STDERR) { + // Only write to stderr if the message is important enough. + if (prio_is_visible_on_stderr(prio)) { + if (safe_write(STDERR_FILENO, start, len)) + flags &= ~DOUTSB_FLAG_STDERR; + } + } + if (flags & DOUTSB_FLAG_OFILE) { + if (safe_write(ofd, start, len)) + flags &= ~DOUTSB_FLAG_OFILE; + } + + *(end+1) = next; + start = end + 1; + } + + _clear_output_buffer(); + + // A value different than EOF (or traits::eof() for other traits) signals success. + // If the function fails, either EOF (or traits::eof() for other traits) is returned or an + // exception is thrown. + return traits_ty::not_eof(c); +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>::handle_stderr_closed() +{ + assert(_dout_lock.is_locked()); + flags &= ~DOUTSB_FLAG_STDERR; +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>::handle_stdout_closed() +{ + assert(_dout_lock.is_locked()); + flags &= ~DOUTSB_FLAG_STDOUT; +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>::read_global_config() +{ + assert(_dout_lock.is_locked()); + flags = 0; + + if (g_conf.log_to_syslog) { + flags |= DOUTSB_FLAG_SYSLOG; + } + if (g_conf.log_to_stdout) { + if (fd_is_open(STDOUT_FILENO)) { + flags |= DOUTSB_FLAG_STDOUT; + } + } + if (fd_is_open(STDERR_FILENO)) { + flags |= DOUTSB_FLAG_STDERR; + } + if (g_conf.log_to_file) { + if (_read_ofile_config()) { + flags |= DOUTSB_FLAG_OFILE; + } + } +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>:: +set_flags(int flags_) +{ + assert(_dout_lock.is_locked()); + flags = flags_; +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>:: +set_prio(int prio) +{ + charT* p = this->pptr(); + *p++ = '\1'; + unsigned char val = (prio + 11); + *p++ = val; + this->pbump(2); +} + +template <typename charT, typename traits> +int DoutStreambuf<charT, traits>::handle_pid_change() +{ + assert(_dout_lock.is_locked()); + if (!(flags & DOUTSB_FLAG_OFILE)) + return 0; + + string new_opath(_calculate_opath()); + if (opath == new_opath) + return 0; + + if (!isym_path.empty()) { + // Re-create the instance symlink + int ret = create_symlink(new_opath, isym_path); + if (ret) { + ostringstream oss; + oss << __func__ << ": failed to (re)create instance symlink"; + primitive_log(oss.str()); + return ret; + } + } + + if (!rsym_path.empty()) { + // Re-create the rank symlink + int ret = create_symlink(new_opath, rsym_path); + if (ret) { + ostringstream oss; + oss << __func__ << ": failed to (re)create rank symlink"; + primitive_log(oss.str()); + return ret; + } + } + + int ret = ::rename(opath.c_str(), new_opath.c_str()); + if (ret) { + int err = errno; + ostringstream oss; + oss << __func__ << ": failed to rename '" << opath << "' to " + << "'" << new_opath << "': " << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return err; + } + + opath = new_opath; + + return 0; +} + +template <typename charT, typename traits> +int DoutStreambuf<charT, traits>::create_rank_symlink(int n) +{ + Mutex::Locker l(_dout_lock); + + if (!(flags & DOUTSB_FLAG_OFILE)) + return 0; + + ostringstream rss; + std::string symlink_dir(_get_symlink_dir()); + rss << symlink_dir << "/" << g_conf.type << "." << n; + string rsym_path_(rss.str()); + int ret = create_symlink(opath, rsym_path_); + if (ret) { + ostringstream oss; + oss << __func__ << ": failed to create rank symlink with n = " + << n << "\n"; + primitive_log(oss.str()); + return ret; + } + + rsym_path = rsym_path_; + return 0; +} + +template <typename charT, typename traits> +std::string DoutStreambuf<charT, traits>::config_to_str() const +{ + assert(_dout_lock.is_locked()); + ostringstream oss; + oss << "g_conf.log_to_syslog = " << g_conf.log_to_syslog << "\n"; + oss << "g_conf.log_to_stdout = " << g_conf.log_to_stdout << "\n"; + oss << "g_conf.log_to_file = " << g_conf.log_to_file << "\n"; + oss << "g_conf.log_file = '" << cpp_str(g_conf.log_file) << "'\n"; + oss << "g_conf.log_dir = '" << cpp_str(g_conf.log_dir) << "'\n"; + oss << "g_conf.g_conf.log_per_instance = '" + << g_conf.log_per_instance << "'\n"; + oss << "flags = 0x" << std::hex << flags << std::dec << "\n"; + oss << "ofd = " << ofd << "\n"; + oss << "opath = '" << opath << "'\n"; + oss << "isym_path = '" << isym_path << "'\n"; + oss << "rsym_path = '" << rsym_path << "'\n"; + oss << "log_sym_history = " << g_conf.log_sym_history << "\n"; + return oss.str(); +} + +// This is called to flush the buffer. +// This is called when we're done with the file stream (or when .flush() is called). +template <typename charT, typename traits> +typename DoutStreambuf<charT, traits>::int_type +DoutStreambuf<charT, traits>::sync() +{ + //std::cout << "flush!" << std::endl; + typename DoutStreambuf<charT, traits>::int_type + ret(this->overflow(traits_ty::eof())); + if (ret == traits_ty::eof()) + return -1; + + return 0; +} + +template <typename charT, typename traits> +typename DoutStreambuf<charT, traits>::int_type +DoutStreambuf<charT, traits>::underflow() +{ + // We can't read from this + // TODO: some more elegant way of preventing callers from trying to get input from this stream + assert(0); +} + +template <typename charT, typename traits> +void DoutStreambuf<charT, traits>::_clear_output_buffer() +{ + // Set up the put pointer. + // Overflow is called when this buffer is filled + this->setp(obuf, obuf + OBUF_SZ - 5); +} + +template <typename charT, typename traits> +std::string DoutStreambuf<charT, traits>::_calculate_opath() const +{ + assert(_dout_lock.is_locked()); + + // If g_conf.log_file was specified, that takes the highest priority + if (!empty(g_conf.log_file)) { + return normalize_relative(g_conf.log_file); + } + + string log_dir; + if (empty(g_conf.log_dir)) + log_dir = normalize_relative("."); + else + log_dir = normalize_relative(g_conf.log_dir); + + if (g_conf.log_per_instance) { + char hostname[255]; + memset(hostname, 0, sizeof(hostname)); + int ret = gethostname(hostname, sizeof(hostname)); + if (ret) { + int err = errno; + ostringstream oss; + oss << __func__ << ": error calling gethostname: " << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return ""; + } + ostringstream oss; + oss << log_dir << "/" << hostname << "." << getpid(); + return oss.str(); + } + else { + ostringstream oss; + oss << log_dir << "/" << g_conf.type << "." << g_conf.id << ".log"; + return oss.str(); + } +} + +template <typename charT, typename traits> +std::string DoutStreambuf<charT, traits>::_get_symlink_dir() const +{ + if (!empty(g_conf.log_sym_dir)) + return normalize_relative(g_conf.log_sym_dir); + else + return get_dirname(opath); +} + +template <typename charT, typename traits> +bool DoutStreambuf<charT, traits>::_read_ofile_config() +{ + int ret; + + isym_path = ""; + rsym_path = ""; + opath = _calculate_opath(); + if (opath.empty()) { + ostringstream oss; + oss << __func__ << ": _calculate_opath failed.\n"; + primitive_log(oss.str()); + return false; + } + + if (empty(g_conf.log_file) && g_conf.log_per_instance) { + // Calculate instance symlink path (isym_path) + ostringstream iss; + std::string symlink_dir(_get_symlink_dir()); + iss << symlink_dir << "/" << g_conf.type << "." << g_conf.id; + isym_path = iss.str(); + + // Rotate isym_path + ret = _rotate_files(isym_path); + if (ret) { + ostringstream oss; + oss << __func__ << ": failed to rotate instance symlinks"; + primitive_log(oss.str()); + return ret; + } + + // Create isym_path + ret = create_symlink(opath, isym_path); + if (ret) { + ostringstream oss; + oss << __func__ << ": failed to create instance symlink"; + primitive_log(oss.str()); + return ret; + } + } + + assert(ofd == -1); + ofd = open(opath.c_str(), + O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IRUSR); + if (ofd < 0) { + int err = errno; + ostringstream oss; + oss << "failed to open log file '" << opath << "': " + << cpp_strerror(err) << "\n"; + primitive_log(oss.str()); + return false; + } + + return true; +} + +template <typename charT, typename traits> +int DoutStreambuf<charT, traits>::_rotate_files(const std::string &base) +{ + // Given a file name base, and a directory like this: + // base + // base.1 + // base.2 + // base.3 + // base.4 + // unrelated_blah + // unrelated_blah.1 + // + // We'll take the following actions: + // base rename to base.1 + // base.1 rename to base.2 + // base.2 rename to base.3 + // base.3 (unlink) + // base.4 (unlink) + // unrelated_blah (do nothing) + // unrelated_blah.1 (do nothing) + + signed int i; + for (i = -1; i < INT_MAX; ++i) { + ostringstream oss; + oss << base; + if (i != -1) + oss << "." << i; + string path(oss.str()); + + if (::access(path.c_str(), R_OK | W_OK)) + break; + } + signed int max_symlink = i - 1; + + for (signed int j = max_symlink; j >= -1; --j) { + ostringstream oss; + oss << base; + if (j != -1) + oss << "." << j; + string path(oss.str()); + + signed int k = j + 1; + if (k >= g_conf.log_sym_history) { + if (::unlink(path.c_str())) { + int err = errno; + ostringstream ess; + ess << __func__ << ": failed to unlink '" << path << "': " + << cpp_strerror(err) << "\n"; + primitive_log(ess.str()); + return err; + } + //*_dout << "---- " << getpid() << " removed " << path << " ----" + // << std::endl; + } + else { + ostringstream pss; + pss << base << "." << k; + string new_path(pss.str()); + if (::rename(path.c_str(), new_path.c_str())) { + int err = errno; + ostringstream ess; + ess << __func__ << ": failed to rename '" << path << "' to " + << "'" << new_path << "': " << cpp_strerror(err) << "\n"; + primitive_log(ess.str()); + return err; + } +// *_dout << "---- " << getpid() << " renamed " << path << " -> " +// << newpath << " ----" << std::endl; + } + } + return 0; +} + +// Explicit template instantiation +template class DoutStreambuf <char>; diff --git a/src/common/DoutStreambuf.h b/src/common/DoutStreambuf.h new file mode 100644 index 00000000000..76968198b24 --- /dev/null +++ b/src/common/DoutStreambuf.h @@ -0,0 +1,106 @@ +// -*- 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) 2010 Dreamhost + * + * 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. + * + */ + +/* + * DoutStreambuf + * + * The stream buffer used by dout + */ +#ifndef CEPH_DOUT_STREAMBUF_H +#define CEPH_DOUT_STREAMBUF_H + +#include <iosfwd> +#include <string> + +template <typename charT, typename traits = std::char_traits<charT> > +class DoutStreambuf : public std::basic_streambuf<charT, traits> +{ +public: + enum dout_streambuf_flags_t { + DOUTSB_FLAG_SYSLOG = 0x01, + DOUTSB_FLAG_STDOUT = 0x02, + DOUTSB_FLAG_STDERR = 0x04, + DOUTSB_FLAG_OFILE = 0x08, + }; + + typedef traits traits_ty; + typedef typename traits_ty::int_type int_type; + typedef typename traits_ty::pos_type pos_type; + typedef typename traits_ty::off_type off_type; + + // The size of the output buffer. + static const size_t OBUF_SZ = 32000; + + DoutStreambuf(); + + // Call when you close stderr. Not strictly necessary, since we would get an + // error the next time we tried to write to stdedrr. But nicer than waiting + // for the error to happen. + void handle_stderr_closed(); + + // Call when you close stdout. + void handle_stdout_closed(); + + // Set the flags based on the global configuration + void read_global_config(); + + // Set the flags directly (for debug use only) + void set_flags(int flags_); + + // Set the priority of the messages being put into the stream + void set_prio(int prio); + + // Call after calling daemon() + // A change in the process ID sometimes requires us to change our output + // path name. + int handle_pid_change(); + + // Create a rank symlink to the log file + int create_rank_symlink(int n); + + std::string config_to_str() const; + +protected: + // Called when the buffer fills up + virtual int_type overflow(int_type c); + + // Called when the buffer is flushed + virtual int_type sync(); + + // Called when we try to read, but there are no more chars in the buffer + virtual int_type underflow(); + +private: + void _clear_output_buffer(); + std::string _calculate_opath() const; + std::string _get_symlink_dir() const; + bool _read_ofile_config(); + int _rotate_files(const std::string &base); + + // Output buffer + charT obuf[OBUF_SZ]; + + // Output flags + int flags; + + // ofile stuff + int ofd; + std::string opath; + + // symlinks + std::string isym_path; + std::string rsym_path; +}; + +#endif diff --git a/src/common/Finisher.cc b/src/common/Finisher.cc index 05fba0c0b3e..7315b9c4f48 100644 --- a/src/common/Finisher.cc +++ b/src/common/Finisher.cc @@ -5,7 +5,7 @@ #include "common/debug.h" #define DOUT_SUBSYS finisher #undef dout_prefix -#define dout_prefix *_dout << dbeginl << "finisher(" << this << ") " +#define dout_prefix *_dout << "finisher(" << this << ") " void Finisher::start() { diff --git a/src/common/LogClient.cc b/src/common/LogClient.cc index 921adcc5485..26f054411d0 100644 --- a/src/common/LogClient.cc +++ b/src/common/LogClient.cc @@ -27,6 +27,7 @@ #include <iostream> #include <errno.h> #include <sys/stat.h> +#include <syslog.h> #ifdef DARWIN #include <sys/param.h> @@ -37,25 +38,59 @@ #include "config.h" -void LogClient::log(log_type type, const char *s) +/* + * Given a clog log_type, return the equivalent syslog priority + */ +static inline int clog_type_to_syslog_prio(clog_type t) +{ + switch (t) { + case CLOG_DEBUG: + return LOG_DEBUG; + case CLOG_INFO: + return LOG_INFO; + case CLOG_WARN: + return LOG_WARNING; + case CLOG_ERROR: + return LOG_ERR; + case CLOG_SEC: + return LOG_CRIT; + default: + assert(0); + return 0; + } +} + +LogClientTemp::LogClientTemp(clog_type type_, LogClient &parent_) + : type(type_), parent(parent_) { - string str(s); - log(type, str); } -void LogClient::log(log_type type, stringstream& ss) +LogClientTemp::LogClientTemp(const LogClientTemp &rhs) + : type(rhs.type), parent(rhs.parent) +{ + // don't want to-- nor can we-- copy the ostringstream +} + +LogClientTemp::~LogClientTemp() +{ + if (ss.peek() != EOF) + parent.do_log(type, ss); +} + +void LogClient::do_log(clog_type type, std::stringstream& ss) { while (!ss.eof()) { string s; getline(ss, s); - log(type, s); + if (!s.empty()) + do_log(type, s); } } -void LogClient::log(log_type type, string& s) +void LogClient::do_log(clog_type type, const std::string& s) { Mutex::Locker l(log_lock); - dout(0) << "log " << (log_type)type << " : " << s << dendl; + dout(0) << "log " << type << " : " << s << dendl; LogEntry e; e.who = messenger->get_myinst(); e.stamp = g_clock.now(); @@ -76,6 +111,33 @@ void LogClient::send_log() void LogClient::_send_log() { + if (g_conf.clog_to_syslog) + _send_log_to_syslog(); + if (g_conf.clog_to_monitors) + _send_log_to_monitors(); +} + +void LogClient::_send_log_to_syslog() +{ + std::deque<LogEntry>::const_reverse_iterator rbegin = log_queue.rbegin(); + std::deque<LogEntry>::const_reverse_iterator rend = log_queue.rend(); + for (std::deque<LogEntry>::const_reverse_iterator a = rbegin; a != rend; ++a) { + const LogEntry entry(*a); + if (entry.seq < last_syslog) + break; + ostringstream oss; + oss << entry; + string str(oss.str()); + syslog(clog_type_to_syslog_prio(entry.type) | LOG_USER, "%s", str.c_str()); + } + if (rbegin != rend) { + const LogEntry entry(*rbegin); + last_syslog = entry.seq; + } +} + +void LogClient::_send_log_to_monitors() +{ if (log_queue.empty()) return; MLog *log = new MLog(monmap->get_fsid(), log_queue); @@ -96,9 +158,14 @@ void LogClient::handle_log_ack(MLogAck *m) dout(10) << "handle_log_ack " << *m << dendl; version_t last = m->last; - while (log_queue.size() && log_queue.begin()->seq <= last) { - dout(10) << " logged " << log_queue.front() << dendl; - log_queue.pop_front(); + + deque<LogEntry>::iterator q = log_queue.begin(); + while (q != log_queue.end()) { + const LogEntry &entry(*q); + if (entry.seq > last) + break; + dout(10) << " logged " << entry << dendl; + q = log_queue.erase(q); } m->put(); } diff --git a/src/common/LogClient.h b/src/common/LogClient.h index a6584739f64..c63bddd7302 100644 --- a/src/common/LogClient.h +++ b/src/common/LogClient.h @@ -15,51 +15,107 @@ #ifndef CEPH_LOGCLIENT_H #define CEPH_LOGCLIENT_H -#include "msg/Dispatcher.h" - +#include "common/LogEntry.h" #include "common/Mutex.h" -#include "include/LogEntry.h" +#include "msg/Dispatcher.h" +#include <iosfwd> #include <sstream> -class Messenger; +class LogClient; class MLog; class MLogAck; -class MonMap; +class Messenger; class MonClient; +class MonMap; -class LogClient : public Dispatcher { - Messenger *messenger; - MonMap *monmap; - MonClient *monc; +class LogClientTemp +{ +public: + LogClientTemp(clog_type type_, LogClient &parent_); + LogClientTemp(const LogClientTemp &rhs); + ~LogClientTemp(); + + template<typename T> + std::ostream& operator<<(const T& rhs) + { + return ss << rhs; + } + +private: + clog_type type; + LogClient &parent; + stringstream ss; +}; +class LogClient : public Dispatcher +{ +public: + enum logclient_flag_t { + NO_FLAGS = 0, + FLAG_SYNC = 0x1, + }; + + LogClient(Messenger *m, MonMap *mm, MonClient *mc, enum logclient_flag_t flags) : + messenger(m), monmap(mm), monc(mc), is_synchronous(flags & FLAG_SYNC), + log_lock("LogClient::log_lock"), last_log(0), last_syslog(0) { } + + void send_log(); + void handle_log_ack(MLogAck *m); + void set_synchronous(bool sync) { is_synchronous = sync; } + + LogClientTemp debug() { + return LogClientTemp(CLOG_DEBUG, *this); + } + void debug(std::stringstream &s) { + do_log(CLOG_DEBUG, s); + } + LogClientTemp info() { + return LogClientTemp(CLOG_INFO, *this); + } + void info(std::stringstream &s) { + do_log(CLOG_INFO, s); + } + LogClientTemp warn() { + return LogClientTemp(CLOG_WARN, *this); + } + void warn(std::stringstream &s) { + do_log(CLOG_WARN, s); + } + LogClientTemp error() { + return LogClientTemp(CLOG_ERROR, *this); + } + void error(std::stringstream &s) { + do_log(CLOG_ERROR, s); + } + LogClientTemp sec() { + return LogClientTemp(CLOG_SEC, *this); + } + void sec(std::stringstream &s) { + do_log(CLOG_SEC, s); + } + +private: + void do_log(clog_type type, std::stringstream& ss); + void do_log(clog_type type, const std::string& s); bool ms_dispatch(Message *m); - bool is_synchronous; void _send_log(); - + void _send_log_to_syslog(); + void _send_log_to_monitors(); void ms_handle_connect(Connection *con); - bool ms_handle_reset(Connection *con) { return false; } void ms_handle_remote_reset(Connection *con) {} - - public: - - // -- log -- + Messenger *messenger; + MonMap *monmap; + MonClient *monc; + bool is_synchronous; Mutex log_lock; - deque<LogEntry> log_queue; version_t last_log; + uint64_t last_syslog; + std::deque<LogEntry> log_queue; - void log(log_type type, const char *s); - void log(log_type type, string& s); - void log(log_type type, stringstream& s); - void send_log(); - void handle_log_ack(MLogAck *m); - void set_synchronous(bool sync) { is_synchronous = sync; } - - LogClient(Messenger *m, MonMap *mm, MonClient *mc=0) : - messenger(m), monmap(mm), monc(mc), is_synchronous(false), - log_lock("LogClient::log_lock"), last_log(0) { } + friend class LogClientTemp; }; #endif diff --git a/src/common/LogEntry.h b/src/common/LogEntry.h new file mode 100644 index 00000000000..04c80b607a4 --- /dev/null +++ b/src/common/LogEntry.h @@ -0,0 +1,144 @@ +// -*- 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) 2004-2006 Sage Weil <sage@newdream.net> + * + * 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 CEPH_LOGENTRY_H +#define CEPH_LOGENTRY_H + +#include "include/types.h" +#include "include/encoding.h" + +typedef enum { + CLOG_DEBUG = 0, + CLOG_INFO = 1, + CLOG_SEC = 2, + CLOG_WARN = 3, + CLOG_ERROR = 4, +} clog_type; + +struct LogEntryKey { + entity_inst_t who; + utime_t stamp; + uint64_t seq; + + LogEntryKey() {} + LogEntryKey(entity_inst_t w, utime_t t, uint64_t s) : who(w), stamp(t), seq(s) {} + + void encode(bufferlist& bl) const { + ::encode(who, bl); + ::encode(stamp, bl); + ::encode(seq, bl); + } + void decode(bufferlist::iterator& bl) { + ::decode(who, bl); + ::decode(stamp, bl); + ::decode(seq, bl); + } +}; +WRITE_CLASS_ENCODER(LogEntryKey) + +static inline bool operator==(const LogEntryKey& l, const LogEntryKey& r) { + return l.who == r.who && l.stamp == r.stamp && l.seq == r.seq; +} + +struct LogEntry { + entity_inst_t who; + utime_t stamp; + uint64_t seq; + clog_type type; + string msg; + + LogEntryKey key() const { return LogEntryKey(who, stamp, seq); } + + void encode(bufferlist& bl) const { + __u8 v = 1; + ::encode(v, bl); + __u16 t = type; + ::encode(who, bl); + ::encode(stamp, bl); + ::encode(seq, bl); + ::encode(t, bl); + ::encode(msg, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 v; + ::decode(v, bl); + __u16 t; + ::decode(who, bl); + ::decode(stamp, bl); + ::decode(seq, bl); + ::decode(t, bl); + type = (clog_type)t; + ::decode(msg, bl); + } +}; +WRITE_CLASS_ENCODER(LogEntry) + +struct LogSummary { + version_t version; + list<LogEntry> tail; + + LogSummary() : version(0) {} + + void add(const LogEntry& e) { + tail.push_back(e); + while (tail.size() > 50) + tail.pop_front(); + } + bool contains(LogEntryKey k) const { + for (list<LogEntry>::const_iterator p = tail.begin(); + p != tail.end(); + p++) + if (p->key() == k) return true; + return false; + } + + void encode(bufferlist& bl) const { + __u8 v = 1; + ::encode(v, bl); + ::encode(version, bl); + ::encode(tail, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 v; + ::decode(v, bl); + ::decode(version, bl); + ::decode(tail, bl); + } +}; +WRITE_CLASS_ENCODER(LogSummary) + +inline ostream& operator<<(ostream& out, clog_type t) +{ + switch (t) { + case CLOG_DEBUG: + return out << "[DBG]"; + case CLOG_INFO: + return out << "[INF]"; + case CLOG_WARN: + return out << "[WRN]"; + case CLOG_ERROR: + return out << "[ERR]"; + case CLOG_SEC: + return out << "[SEC]"; + default: + return out << "[???]"; + } +} + +inline ostream& operator<<(ostream& out, const LogEntry& e) +{ + return out << e.stamp << " " << e.who << " " << e.seq << " : " << e.type << " " << e.msg; +} + +#endif diff --git a/src/common/Thread.h b/src/common/Thread.h index a567d2dbac4..e7da795dbdd 100644 --- a/src/common/Thread.h +++ b/src/common/Thread.h @@ -75,7 +75,7 @@ class Thread { if (r) { char buf[80]; - generic_derr(0) << "pthread_create failed with message: " << strerror_r(r, buf, sizeof(buf)) << dendl; + generic_dout(0) << "pthread_create failed with message: " << strerror_r(r, buf, sizeof(buf)) << dendl; } else { _num_threads.inc(); generic_dout(10) << "thread " << thread_id << " start" << dendl; @@ -84,7 +84,7 @@ class Thread { } int join(void **prval = 0) { if (thread_id == 0) { - generic_derr(0) << "WARNING: join on thread that was never started" << dendl; + generic_dout(0) << "WARNING: join on thread that was never started" << dendl; assert(0); return -EINVAL; // never started. } @@ -93,17 +93,17 @@ class Thread { if (status != 0) { switch (status) { case -EINVAL: - generic_derr(0) << "thread " << thread_id << " join status = EINVAL" << dendl; + generic_dout(0) << "thread " << thread_id << " join status = EINVAL" << dendl; break; case -ESRCH: - generic_derr(0) << "thread " << thread_id << " join status = ESRCH" << dendl; + generic_dout(0) << "thread " << thread_id << " join status = ESRCH" << dendl; assert(0); break; case -EDEADLK: - generic_derr(0) << "thread " << thread_id << " join status = EDEADLK" << dendl; + generic_dout(0) << "thread " << thread_id << " join status = EDEADLK" << dendl; break; default: - generic_derr(0) << "thread " << thread_id << " join status = " << status << dendl; + generic_dout(0) << "thread " << thread_id << " join status = " << status << dendl; } assert(0); // none of these should happen. } diff --git a/src/common/Timer.cc b/src/common/Timer.cc index 7a3439e37f1..9980790b36e 100644 --- a/src/common/Timer.cc +++ b/src/common/Timer.cc @@ -22,7 +22,7 @@ #define DOUT_SUBSYS timer #undef dout_prefix -#define dout_prefix *_dout << dbeginl << "timer(" << this << ")." +#define dout_prefix *_dout << "timer(" << this << ")." #include <sstream> #include <signal.h> diff --git a/src/common/WorkQueue.cc b/src/common/WorkQueue.cc index cae4cef6c8f..a3f67e0a0d2 100644 --- a/src/common/WorkQueue.cc +++ b/src/common/WorkQueue.cc @@ -19,7 +19,7 @@ #define DOUT_SUBSYS tp #undef dout_prefix -#define dout_prefix *_dout << dbeginl << name << " " +#define dout_prefix *_dout << name << " " void ThreadPool::worker() diff --git a/src/common/common_init.cc b/src/common/common_init.cc index f634247f8cb..a5c02b9fff1 100644 --- a/src/common/common_init.cc +++ b/src/common/common_init.cc @@ -44,13 +44,6 @@ void common_init(std::vector<const char*>& args, const char *module_type, bool i } #endif //HAVE_LIBTCMALLOC - if (g_conf.log_file && g_conf.log_file[0]) - g_conf.log_to_stdout = false; - - // open log file? - if (!g_conf.log_to_stdout) - _dout_open_log(); - if (init_keys && is_supported_auth(CEPH_AUTH_CEPHX)) { g_keyring.load(g_conf.keyring); diff --git a/src/common/debug.cc b/src/common/debug.cc index 86def0548a1..10cd6ceed9e 100644 --- a/src/common/debug.cc +++ b/src/common/debug.cc @@ -1,212 +1,70 @@ - -#include "include/types.h" -#include "config.h" -#include "debug.h" #include "Mutex.h" -#include "Clock.h" - #include "ceph_ver.h" +#include "common/DoutStreambuf.h" +#include "config.h" +#include "debug.h" #include <errno.h> #include <fstream> #include <iostream> -using namespace std; - -#define _STR(x) #x -#define STRINGIFY(x) _STR(x) // debug output -Mutex _dout_lock("_dout_lock", false, false /* no lockdep */); -ostream *_dout = &std::cout; -ostream *_derr = &std::cerr; -char _dout_dir[PATH_MAX] = {0}; -char _dout_symlink_dir[PATH_MAX] = {0}; -char _dout_file[PATH_MAX] = {0}; -char _dout_path[PATH_MAX] = {0}; -char _dout_rank_symlink_path[PATH_MAX] = {0}; -char _dout_name_symlink_path[PATH_MAX] = {0}; -char *_dout_symlink_target = 0; // _dout_path or _dout_file -bool _dout_is_open = false; +std::ostream *_dout = NULL; +DoutStreambuf <char> *_doss = NULL; bool _dout_need_open = true; -std::ofstream _dout_out; - -static void normalize_relative(const char *from, char *to, int tolen) -{ - if (from[0] == '/') - strncpy(to, from, tolen); - else { - char *c = getcwd(to, tolen); - assert(c); - strncat(to, "/", tolen); - strncat(to, from, tolen); - } -} - -static void build_log_paths() -{ - if (g_conf.log_file && g_conf.log_file[0]) { - normalize_relative(g_conf.log_file, _dout_path, sizeof(_dout_path)); - } else { - if (g_conf.log_per_instance) { - char hostname[80]; - gethostname(hostname, 79); - snprintf(_dout_file, sizeof(_dout_file), "%s.%d", hostname, getpid()); - } else { - snprintf(_dout_file, sizeof(_dout_file), "%s.%s.log", g_conf.type, g_conf.id); - } - snprintf(_dout_path, sizeof(_dout_path), "%s/%s", _dout_dir, _dout_file); - } -} - -static bool log_to_file() -{ - return (g_conf.log_dir || g_conf.log_file) && !g_conf.log_to_stdout; -} - -static int create_symlink(const char *from) -{ - ::unlink(from); - int r = ::symlink(_dout_symlink_target, from); - if (r) { - char buf[80]; - *_dout << "---- " << getpid() << " failed to symlink " << _dout_symlink_target - << " from " << from - << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl; - } - return r; -} - -static void rotate_file(const char *fn, int max) -{ - char a[200], b[200]; - // rotate out old - int n = 0; - while (1) { - struct stat st; - snprintf(a, sizeof(a), "%s.%lld", fn, (long long)n); - if (::lstat(a, &st) != 0) - break; - n++; - } - while (n >= 0) { - if (n) - snprintf(a, sizeof(a), "%s.%lld", fn, (long long)n-1); - else - snprintf(a, sizeof(a), "%s", fn); - if (n >= max) { - ::unlink(a); - *_dout << "---- " << getpid() << " removed " << a << " ----" << std::endl; - } else { - snprintf(b, sizeof(b), "%s.%lld", fn, (long long)n); - ::rename(a, b); - *_dout << "---- " << getpid() << " renamed " << a << " -> " << b << " ----" << std::endl; - } - n--; - } -} - -static int create_name_symlink() -{ - int r = 0; - if (log_to_file() && g_conf.log_per_instance && !(g_conf.log_file && g_conf.log_file[0])) { - snprintf(_dout_name_symlink_path, sizeof(_dout_name_symlink_path), - "%s/%s.%s", _dout_symlink_dir, g_conf.type, g_conf.id); - - rotate_file(_dout_name_symlink_path, g_conf.log_sym_history); - r = create_symlink(_dout_name_symlink_path); - } - return r; -} +Mutex _dout_lock("_dout_lock", false, false /* no lockdep */); +#define _STR(x) #x +#define STRINGIFY(x) _STR(x) void _dout_open_log() { - bool need_symlink = false; - - // logging enabled? - if (!log_to_file()) { - _dout_need_open = false; - return; - } - - // calculate log dir, filename, etc. - // do this _once_. - if (!_dout_path[0]) { - - // normalize paths - normalize_relative(g_conf.log_dir, _dout_dir, sizeof(_dout_dir)); - if (!g_conf.log_sym_dir) - g_conf.log_sym_dir = strdup(g_conf.log_dir); - normalize_relative(g_conf.log_sym_dir, _dout_symlink_dir, sizeof(_dout_symlink_dir)); + assert(_dout_need_open); + assert(_dout_lock.is_locked()); - // make symlink targets absolute or relative? - if ((g_conf.log_file && g_conf.log_file[0]) || - strcmp(_dout_symlink_dir, _dout_dir) == 0) - _dout_symlink_target = _dout_file; - else - _dout_symlink_target = _dout_path; - - build_log_paths(); - - need_symlink = true; + if (!_doss) { + _doss = new DoutStreambuf <char>(); } - - _dout_out.close(); - _dout_out.open(_dout_path, ios::out | ios::app); - if (!_dout_out.is_open()) { - std::cerr << "error opening output file " << _dout_path << std::endl; - _dout = &std::cout; - } else { - _dout_need_open = false; - _dout_is_open = true; - _dout = &_dout_out; - *_dout << g_clock.now() << " --- " << getpid() << " opened log " - << _dout_path << " ---" << std::endl; + _doss->read_global_config(); + if (!_dout) { + _dout = new std::ostream(_doss); } - *_dout << "ceph version " << VERSION << " (commit:" << STRINGIFY(CEPH_GIT_VER) << ")" << std::endl; - if (need_symlink) - create_name_symlink(); + *_dout << "ceph version " << VERSION << " (commit:" + << STRINGIFY(CEPH_GIT_VER) << ")" << std::endl; + _dout_need_open = false; } -int dout_rename_output_file() // after calling daemon() +int dout_handle_daemonize() { Mutex::Locker l(_dout_lock); - if (log_to_file() && g_conf.log_per_instance) { - char oldpath[PATH_MAX]; - char hostname[80]; - gethostname(hostname, 79); - - strcpy(oldpath, _dout_path); - - build_log_paths(); - - *_dout << "---- " << getpid() << " renamed log " << oldpath << " -> " << _dout_path << " ----" << std::endl; - ::rename(oldpath, _dout_path); - - // $type.$id symlink - if (g_conf.log_per_instance && _dout_name_symlink_path[0]) - create_symlink(_dout_name_symlink_path); - if (_dout_rank_symlink_path[0]) - create_symlink(_dout_rank_symlink_path); - } - return 0; + _doss->handle_stdout_closed(); + _doss->handle_stderr_closed(); + return _doss->handle_pid_change(); } -int dout_create_rank_symlink(int64_t n) +int dout_create_rank_symlink(int n) { Mutex::Locker l(_dout_lock); - int r = 0; - if (log_to_file() && !(g_conf.log_file && g_conf.log_file[0])) { - if (_dout_need_open) - _dout_open_log(); + return _doss->create_rank_symlink(n); +} - snprintf(_dout_rank_symlink_path, sizeof(_dout_rank_symlink_path), - "%s/%s%lld", _dout_symlink_dir, g_conf.type, (long long)n); - r = create_symlink(_dout_rank_symlink_path); +void hex2str(const char *s, int len, char *buf, int dest_len) +{ + int pos = 0; + for (int i=0; i<len && pos<dest_len; i++) { + if (i && !(i%8)) + pos += snprintf(&buf[pos], dest_len-pos, " "); + if (i && !(i%16)) + pos += snprintf(&buf[pos], dest_len-pos, "\n"); + pos += snprintf(&buf[pos], dest_len-pos, "%.2x ", (int)(unsigned char)s[i]); } - return r; } - - +void hexdump(string msg, const char *s, int len) +{ + int buf_len = len*4; + char buf[buf_len]; + hex2str(s, len, buf, buf_len); + generic_dout(0) << msg << ":\n" << buf << dendl; +} diff --git a/src/common/debug.h b/src/common/debug.h index 7b60c38abe8..af6fe9957e1 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -1,117 +1,87 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// -*- 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) 2004-2010 Sage Weil <sage@newdream.net> + * Copyright (C) 2010 Dreamhost + * + * 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 CEPH_DEBUG_H #define CEPH_DEBUG_H -#include "include/assert.h" -#include "Mutex.h" #include "Clock.h" +#include "Mutex.h" +#include "common/DoutStreambuf.h" +#include "common/likely.h" +#include "include/assert.h" -#include <ostream> -using std::ostream; - -// the streams -extern ostream *_dout; -extern ostream *_derr; - -extern Mutex _dout_lock; +#include <iosfwd> +extern std::ostream *_dout; +extern DoutStreambuf <char> *_doss; extern bool _dout_need_open; -extern bool _dout_is_open; +extern Mutex _dout_lock; extern void _dout_open_log(); -static inline void dout_open_log() { - _dout_lock.Lock(); - _dout_open_log(); - _dout_lock.Unlock(); -} -extern int dout_rename_output_file(); // after calling daemon() -extern int dout_create_rank_symlink(int64_t n); +extern int dout_handle_daemonize(); -static inline void _dout_check_log() { - _dout_lock.Lock(); - if (_dout_need_open) - _dout_open_log(); - _dout_lock.Unlock(); -} +extern int dout_create_rank_symlink(int n); -static inline void _dout_begin_line() { +static inline void _dout_begin_line(int prio) { _dout_lock.Lock(); - if (_dout_need_open) + if (unlikely(_dout_need_open)) _dout_open_log(); - *_dout << g_clock.now() << " " << std::hex << pthread_self() << std::dec << " "; -} -static void _dout_begin_line_static() { - _dout_begin_line(); -} -static inline void _dout_end_line() { - _dout_lock.Unlock(); -} + // Put priority information into dout + _doss->sputc(1); + _doss->sputc(prio + 11); -struct _dbeginl_t { _dbeginl_t(int) {} }; -static const _dbeginl_t dbeginl = 0; -inline ostream& operator<<(ostream& out, _dbeginl_t) { - _dout_begin_line(); - return out; + // Some information that goes in every dout message + *_dout << g_clock.now() << " " << std::hex << pthread_self() + << std::dec << " "; } -struct _dbeginlstatic_t { _dbeginlstatic_t(int) {} }; -static const _dbeginlstatic_t dbeginlstatic = 0; -inline ostream& operator<<(ostream& out, _dbeginlstatic_t) { - _dout_begin_line_static(); - return out; +static inline void _dout_end_line() { + _dout_lock.Unlock(); } // intentionally conflict with endl class _bad_endl_use_dendl_t { public: _bad_endl_use_dendl_t(int) {} }; static const _bad_endl_use_dendl_t endl = 0; -inline ostream& operator<<(ostream& out, _bad_endl_use_dendl_t) { +inline std::ostream& operator<<(std::ostream& out, _bad_endl_use_dendl_t) { assert(0 && "you are using the wrong endl.. use std::endl or dendl"); return out; } - // generic macros -#define generic_dout(x) do { if ((x) <= g_conf.debug) { *_dout << dbeginl -#define generic_derr(x) do { if ((x) <= g_conf.debug) { *_derr << dbeginl +#define generic_dout(x) do { if ((x) <= g_conf.debug) {\ + _dout_begin_line(x); *_dout -#define pdout(x,p) do { if ((x) <= (p)) { *_dout << dbeginl +#define pdout(x,p) do { if ((x) <= (p)) {\ + _dout_begin_line(x); *_dout #define debug_DOUT_SUBSYS debug -#define dout_prefix *_dout << dbeginlstatic +#define dout_prefix *_dout #define DOUT_CONDVAR(x) g_conf.debug_ ## x #define XDOUT_CONDVAR(x) DOUT_CONDVAR(x) #define DOUT_COND(l) l <= XDOUT_CONDVAR(DOUT_SUBSYS) -#define dout(l) do { if (DOUT_COND(l)) { dout_prefix -#define derr(l) do { if (DOUT_COND(l)) { dout_prefix +#define dout(l) do { if (DOUT_COND(l)) {\ + _dout_begin_line(l); dout_prefix #define dendl std::endl; _dout_end_line(); } } while (0) -inline static void hex2str(const char *s, int len, char *buf, int dest_len) -{ - int pos = 0; - for (int i=0; i<len && pos<dest_len; i++) { - if (i && !(i%8)) - pos += snprintf(&buf[pos], dest_len-pos, " "); - if (i && !(i%16)) - pos += snprintf(&buf[pos], dest_len-pos, "\n"); - pos += snprintf(&buf[pos], dest_len-pos, "%.2x ", (int)(unsigned char)s[i]); - } -} - -inline static void hexdump(string msg, const char *s, int len) -{ - int buf_len = len*4; - char buf[buf_len]; - hex2str(s, len, buf, buf_len); - generic_dout(0) << msg << ":\n" << buf << dendl; -} - +extern void hex2str(const char *s, int len, char *buf, int dest_len); +extern void hexdump(string msg, const char *s, int len); #endif diff --git a/src/common/likely.h b/src/common/likely.h new file mode 100644 index 00000000000..e8146a3f69e --- /dev/null +++ b/src/common/likely.h @@ -0,0 +1,24 @@ +// -*- 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) 2010 Dreamhost + * + * 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 CEPH_LIKELY_DOT_H +#define CEPH_LIKELY_DOT_H + +/* + * Likely / Unlikely macros + */ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +#endif |