In favor of the simpler StackStreamBuffer.
Signed-off-by: Patrick Donnelly <pdonnell@redhat.com>
set(common_srcs
AsyncOpTracker.cc
BackTrace.cc
- CachedPrebufferedStreambuf.cc
ConfUtils.cc
Cycles.cc
DecayCounter.cc
Mutex.cc
OutputDataSocket.cc
PluginRegistry.cc
- PrebufferedStreambuf.cc
PriorityCache.cc
Readahead.cc
RefCountedObj.cc
+++ /dev/null
-#include "common/CachedPrebufferedStreambuf.h"
-#include <string.h>
-
-// std::unique cannot be used here, as deletion will not clear value,
-// but thread variable will still exist, causing free-memory-read
-struct cached_os_t
-{
- CachedPrebufferedStreambuf* streambuf;
- cached_os_t()
- : streambuf(new CachedPrebufferedStreambuf)
- {}
- ~cached_os_t() {
- delete streambuf;
- streambuf = nullptr;
- }
-};
-
-thread_local cached_os_t t_os;
-
-CachedPrebufferedStreambuf::~CachedPrebufferedStreambuf()
-{
- if (this == t_os.streambuf) {
- // we are deleting thread's PrebufferedStreambuf,
- // clear it so we can create it cleanly again without error
- t_os.streambuf = nullptr;
- }
-}
-
-// lock state of streambuf and detach buffer
-void CachedPrebufferedStreambuf::finish()
-{
- data->m_pptr = this->pptr();
- data = nullptr;
- if (this != t_os.streambuf) {
- // this is extra formatter, not useful anymore
- delete this;
- }
-}
-
-CachedPrebufferedStreambuf*
-CachedPrebufferedStreambuf::create(prebuffered_data* data)
-{
- CachedPrebufferedStreambuf* streambuf;
-
- if (t_os.streambuf == nullptr || /*this can happen only on process cleanup*/
- t_os.streambuf->in_use() /*this happens when we do recursion in logging*/ ) {
- streambuf = new CachedPrebufferedStreambuf();
- } else {
- streambuf = t_os.streambuf;
- // reset ios flags (failbit, badbit) from previous use
- streambuf->get_ostream().clear();
- }
- streambuf->data = data;
- streambuf->setp(data->m_buf, data->m_buf + data->m_buf_len);
- // so we underflow on first read
- streambuf->setg(0, 0, 0);
- return streambuf;
-}
-
-CachedPrebufferedStreambuf::int_type CachedPrebufferedStreambuf::overflow(int_type c)
-{
- int old_len = data->m_overflow.size();
- if (old_len == 0) {
- data->m_overflow.resize(80);
- } else {
- data->m_overflow.resize(old_len * 2);
- }
- data->m_overflow[old_len] = c;
- this->setp(&data->m_overflow[old_len + 1], &*data->m_overflow.begin() + data->m_overflow.size());
- return traits_type::not_eof(c);
-}
-
-CachedPrebufferedStreambuf::int_type CachedPrebufferedStreambuf::underflow()
-{
- if (this->gptr() == 0) {
- // first read; start with the static buffer
- if (!data->m_overflow.empty())
- // there is overflow, so start with entire prealloc buffer
- this->setg(data->m_buf, data->m_buf, data->m_buf + data->m_buf_len);
- else if (this->pptr() == data->m_buf)
- // m_buf is empty
- return traits_type::eof(); // no data
- else
- // set up portion of m_buf we've filled
- this->setg(data->m_buf, data->m_buf, this->pptr());
- return *this->gptr();
- }
- if (this->gptr() == data->m_buf + data->m_buf_len && data->m_overflow.size()) {
- // at end of m_buf; continue with the overflow string
- this->setg(&data->m_overflow[0], &data->m_overflow[0], this->pptr());
- return *this->gptr();
- }
-
- // otherwise we must be at the end (of m_buf and/or m_overflow)
- return traits_type::eof();
-}
-
-/// return a string copy (inefficiently)
-std::string prebuffered_data::get_str() const
-{
- if (!m_overflow.empty()) {
- std::string s(m_buf, m_buf + m_buf_len);
- s.append(&m_overflow[0], m_pptr - &m_overflow[0]);
- return s;
- } else if (m_pptr == m_buf) {
- return std::string();
- } else {
- return std::string(m_buf, m_pptr - m_buf);
- }
-}
-
-// returns current size of content
-size_t prebuffered_data::size() const
-{
- if (m_overflow.empty()) {
- return m_pptr - m_buf;
- } else {
- return m_buf_len + m_pptr - &m_overflow[0];
- }
-}
-
-// extracts up to avail chars of content
-int prebuffered_data::snprintf(char* dst, size_t avail) const
-{
- size_t len_a;
- size_t len_b;
- if (!m_overflow.empty()) {
- len_a = m_buf_len;
- len_b = m_pptr - &m_overflow[0];
- } else {
- len_a = m_pptr - m_buf;
- len_b = 0;
- }
- if (avail > len_a + len_b) {
- memcpy(dst, m_buf, len_a);
- memcpy(dst + m_buf_len, m_overflow.c_str(), len_b);
- dst[len_a + len_b] = 0;
- } else {
- if (avail > len_a) {
- memcpy(dst, m_buf, len_a);
- memcpy(dst + m_buf_len, m_overflow.c_str(), avail - len_a - 1);
- dst[avail - 1] = 0;
- } else {
- memcpy(dst, m_buf, avail - 1);
- dst[avail - 1] = 0;
- }
- }
- return len_a + len_b;
-}
+++ /dev/null
-#ifndef CEPH_COMMON_CACHED_PREBUFFEREDSTREAMBUF_H
-#define CEPH_COMMON_CACHED_PREBUFFEREDSTREAMBUF_H
-
-#include <streambuf>
-#include <atomic>
-#include <ostream>
-
-/**
- * streambuf using existing buffer, overflowing into a std::string
- *
- * A simple streambuf that uses a preallocated buffer for small
- * strings, and overflows into a std::string when necessary. If the
- * preallocated buffer size is chosen well, we can optimize for the
- * common case and overflow to a slower heap-allocated buffer when
- * necessary.
- */
-struct prebuffered_data
-{
-private:
- char *m_buf;
- size_t m_buf_len;
- char *m_pptr;
- std::string m_overflow;
-
-public:
- prebuffered_data(char* buf, size_t buf_len)
- : m_buf(buf), m_buf_len(buf_len), m_pptr(nullptr) {}
-
- /// return a string copy (inefficiently)
- std::string get_str() const;
-
- // returns current size of content
- size_t size() const;
-
- // extracts up to avail chars of content
- int snprintf(char* dst, size_t avail) const;
- friend class CachedPrebufferedStreambuf;
-};
-
-class CachedPrebufferedStreambuf final : public std::streambuf
-{
-public:
- static CachedPrebufferedStreambuf* create(prebuffered_data* d);
-
- std::ostream& get_ostream() {
- return os;
- }
-
- // called when the buffer fills up
- int_type overflow(int_type c) override;
-
- // called when we read and need more data
- int_type underflow() override;
-
- // signals that formatting log has finished
- void finish();
-
-private:
- CachedPrebufferedStreambuf()
- : data(nullptr), os(this) {}
- ~CachedPrebufferedStreambuf();
-
- // determines if instance is currently used for formatting log
- bool in_use() const {
- return data != nullptr;
- }
-
- prebuffered_data* data;
- std::ostream os;
- friend class cached_os_t;
-};
-
-#endif
+++ /dev/null
-
-#include "common/PrebufferedStreambuf.h"
-#include <string.h>
-PrebufferedStreambuf::PrebufferedStreambuf(char *buf, size_t len)
- : m_buf(buf), m_buf_len(len)
-{
- // init output buffer
- this->setp(m_buf, m_buf + m_buf_len);
-
- // so we underflow on first read
- this->setg(0, 0, 0);
-}
-
-PrebufferedStreambuf::int_type PrebufferedStreambuf::overflow(int_type c)
-{
- int old_len = m_overflow.size();
- if (old_len == 0) {
- m_overflow.resize(80);
- } else {
- m_overflow.resize(old_len * 2);
- }
- m_overflow[old_len] = c;
- this->setp(&m_overflow[old_len + 1], &*m_overflow.begin() + m_overflow.size());
- return std::char_traits<char>::not_eof(c);
-}
-
-PrebufferedStreambuf::int_type PrebufferedStreambuf::underflow()
-{
- if (this->gptr() == 0) {
- // first read; start with the static buffer
- if (m_overflow.size())
- // there is overflow, so start with entire prealloc buffer
- this->setg(m_buf, m_buf, m_buf + m_buf_len);
- else if (this->pptr() == m_buf)
- // m_buf is empty
- return traits_ty::eof(); // no data
- else
- // set up portion of m_buf we've filled
- this->setg(m_buf, m_buf, this->pptr());
- return *this->gptr();
- }
- if (this->gptr() == m_buf + m_buf_len && m_overflow.size()) {
- // at end of m_buf; continue with the overflow string
- this->setg(&m_overflow[0], &m_overflow[0], this->pptr());
- return *this->gptr();
- }
-
- // otherwise we must be at the end (of m_buf and/or m_overflow)
- return traits_ty::eof();
-}
-
-std::string PrebufferedStreambuf::get_str() const
-{
- if (m_overflow.size()) {
- std::string s(m_buf, m_buf + m_buf_len);
- s.append(&m_overflow[0], this->pptr() - &m_overflow[0]);
- return s;
- } else if (this->pptr() == m_buf) {
- return std::string();
- } else {
- return std::string(m_buf, this->pptr() - m_buf);
- }
-}
-// returns current size of content
-size_t PrebufferedStreambuf::size() const
-{
- if (m_overflow.size() == 0) {
- return this->pptr() - m_buf;
- } else {
- return m_buf_len + this->pptr() - &m_overflow[0];
- }
-}
-
-// extracts up to avail chars of content
-int PrebufferedStreambuf::snprintf(char* dst, size_t avail) const
-{
- size_t o_size = m_overflow.size();
- size_t len_a;
- size_t len_b;
- if (o_size>0) {
- len_a = m_buf_len;
- len_b = this->pptr() - &m_overflow[0];
- } else {
- len_a = this->pptr() - m_buf;
- len_b = 0;
- }
- if (avail > len_a + len_b) {
- memcpy(dst, m_buf, len_a);
- memcpy(dst + m_buf_len, m_overflow.c_str(), len_b);
- dst[len_a + len_b] = 0;
- } else {
- if (avail > len_a) {
- memcpy(dst, m_buf, len_a);
- memcpy(dst + m_buf_len, m_overflow.c_str(), avail - len_a - 1);
- dst[avail - 1] = 0;
- } else {
- memcpy(dst, m_buf, avail - 1);
- dst[avail - 1] = 0;
- }
- }
- return len_a + len_b;
-}
+++ /dev/null
-#ifndef CEPH_COMMON_PREBUFFEREDSTREAMBUF_H
-#define CEPH_COMMON_PREBUFFEREDSTREAMBUF_H
-
-#include <streambuf>
-
-/**
- * streambuf using existing buffer, overflowing into a std::string
- *
- * A simple streambuf that uses a preallocated buffer for small
- * strings, and overflows into a std::string when necessary. If the
- * preallocated buffer size is chosen well, we can optimize for the
- * common case and overflow to a slower heap-allocated buffer when
- * necessary.
- */
-class PrebufferedStreambuf
- : public std::basic_streambuf<char, std::basic_string<char>::traits_type>
-{
- char *m_buf;
- size_t m_buf_len;
- std::string m_overflow;
-
- typedef std::char_traits<char> traits_ty;
- typedef traits_ty::int_type int_type;
- typedef traits_ty::pos_type pos_type;
- typedef traits_ty::off_type off_type;
-
-public:
- PrebufferedStreambuf(char *buf, size_t len);
-
- // called when the buffer fills up
- int_type overflow(int_type c) override;
-
- // called when we read and need more data
- int_type underflow() override;
-
- /// return a string copy (inefficiently)
- std::string get_str() const;
-
- // returns current size of content
- size_t size() const;
-
- // extracts up to avail chars of content
- int snprintf(char* dst, size_t avail) const;
-};
-
-#endif
#include "log/Log.h"
#include "common/Clock.h"
-#include "common/PrebufferedStreambuf.h"
#include "include/coredumpctl.h"
#include "SubsystemMap.h"
target_link_libraries(unittest_striper global ${BLKID_LIBRARIES})
endif()
-# unittest_prebufferedstreambuf
-add_executable(unittest_prebufferedstreambuf
- test_prebufferedstreambuf.cc
- )
-add_ceph_unittest(unittest_prebufferedstreambuf)
-target_link_libraries(unittest_prebufferedstreambuf global)
-
# unittest_str_list
add_executable(unittest_str_list
test_str_list.cc
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "common/PrebufferedStreambuf.h"
-#include "gtest/gtest.h"
-
-TEST(PrebufferedStreambuf, Empty)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::istream is(&sb);
- std::string out;
- getline(is, out);
- ASSERT_EQ("", out);
-}
-
-TEST(PrebufferedStreambuf, Simple)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::ostream os(&sb);
- os << "test";
-
- std::istream is(&sb);
- std::string out;
- getline(is, out);
- ASSERT_EQ("test", out);
-}
-
-TEST(PrebufferedStreambuf, Multiline)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::ostream os(&sb);
- const char *s = "this is a line\nanother line\nand a third\nwhee!\n";
- os << s;
-
- std::istream is(&sb);
- std::string out;
- getline(is, out, is.widen(0));
- ASSERT_EQ(s, out);
-}
-
-TEST(PrebufferedStreambuf, Withnull)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::ostream os(&sb);
- std::string s("null \0 and more", 15);
- os << s;
-
- std::istream is(&sb);
- std::string out;
- getline(is, out);
- ASSERT_EQ(s, out);
-}
-
-TEST(PrebufferedStreambuf, SimpleOverflow)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::ostream os(&sb);
- const char *s = "hello, this is longer than buf[10]";
- os << s;
-
- ASSERT_EQ(s, sb.get_str());
-
- std::istream is(&sb);
- std::string out;
- getline(is, out);
- ASSERT_EQ(s, out);
-}
-
-TEST(PrebufferedStreambuf, ManyOverflow)
-{
- char buf[10];
- PrebufferedStreambuf sb(buf, sizeof(buf));
-
- std::ostream os(&sb);
- const char *s = "hello, this way way way way way way way way way way way way way way way way way way way way way way way way way _way_ longer than buf[10]";
- os << s;
-
- ASSERT_EQ(s, sb.get_str());
-
- std::istream is(&sb);
- std::string out;
- getline(is, out);
- ASSERT_EQ(s, out);
-}
-