1
0
Fork 0

[3.4] fix ASAN issues in arangosearch (#7027)

* update iresearch

* update iresearch
This commit is contained in:
Andrey Abramov 2018-10-23 22:30:15 +03:00 committed by GitHub
parent 168755f377
commit 0c6cf212e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 328 additions and 197 deletions

View File

@ -657,6 +657,10 @@ install:
- eval "${SET_ENV}"
- which bison
- bison --version
- which ${CC}
- ${CC} --version
- which ${CXX}
- ${CXX} --version
############################################################################
# All the dependencies are installed in ${TRAVIS_BUILD_DIR}/deps/

View File

@ -24,6 +24,7 @@
#include "shared.hpp"
#include "token_streams.hpp"
#include "utils/bit_utils.hpp"
#include "utils/string_utils.hpp"
NS_LOCAL
@ -134,25 +135,25 @@ bytes_ref numeric_token_stream::numeric_term::value(
switch (type) {
case NT_LONG: {
typedef numeric_utils::numeric_traits<int64_t> traits_t;
oversize(buf, traits_t::size());
string_utils::oversize(buf, traits_t::size());
return bytes_ref(&(buf[0]), traits_t::encode(val.i64, &(buf[0]), shift));
}
case NT_DBL: {
typedef numeric_utils::numeric_traits<double_t> traits_t;
oversize(buf, traits_t::size());
string_utils::oversize(buf, traits_t::size());
return bytes_ref(&(buf[0]), traits_t::encode(val.i64, &(buf[0]), shift));
}
case NT_INT: {
typedef numeric_utils::numeric_traits<int32_t> traits_t;
oversize(buf, traits_t::size());
string_utils::oversize(buf, traits_t::size());
return bytes_ref(&(buf[0]), traits_t::encode(val.i32, &(buf[0]), shift));
}
case NT_FLOAT: {
typedef numeric_utils::numeric_traits<float_t> traits_t;
oversize(buf, traits_t::size());
string_utils::oversize(buf, traits_t::size());
return bytes_ref(&(buf[0]), traits_t::encode(val.i32, &(buf[0]), shift));
}

View File

@ -62,21 +62,10 @@ struct IRESEARCH_API error_base: std::exception {
// -----------------------------------------------------------------------------
class IRESEARCH_API detailed_error_base: public error_base {
public:
explicit detailed_error_base(const char* error): error_(error) {}
explicit detailed_error_base(std::string&& error) NOEXCEPT
: error_(std::move(error)) {
}
detailed_error_base(const detailed_error_base& other)
: error_(other.error_) {
}
detailed_error_base(detailed_error_base&& other) NOEXCEPT
: error_(std::move(other.error_)) {
}
detailed_error_base& operator=(const detailed_error_base& other) = delete;
detailed_error_base& operator=(detailed_error_base&& other) NOEXCEPT = delete;
virtual const char* what() const NOEXCEPT final { return error_.c_str(); }
private:
@ -117,11 +106,9 @@ struct IRESEARCH_API eof_error: io_error {
// ----------------------------------------------------------------------------
struct IRESEARCH_API detailed_io_error: public detailed_error_base {
public:
explicit detailed_io_error(std::string&& error)
: detailed_error_base(std::move(error)) {
}
DECLARE_ERROR_CODE(io_error);
template<typename T>
detailed_io_error(T&& error): detailed_error_base(std::forward<T>(error)) {}
virtual ErrorCode code() const NOEXCEPT override { return CODE; }
};
@ -168,11 +155,9 @@ struct IRESEARCH_API index_not_found: error_base {
// index_error
// ----------------------------------------------------------------------------
struct IRESEARCH_API index_error: detailed_error_base {
explicit index_error(std::string&& error)
: detailed_error_base(std::move(error)) {
}
DECLARE_ERROR_CODE(index_error);
template<typename T>
index_error(T&& error): detailed_error_base(std::forward<T>(error)) {}
virtual ErrorCode code() const NOEXCEPT override { return CODE; }
};
@ -205,4 +190,4 @@ struct IRESEARCH_API illegal_state: error_base {
NS_END
#endif
#endif

View File

@ -28,33 +28,34 @@
#include "formats/formats.hpp"
#include <sstream>
NS_ROOT
void validate_footer(iresearch::index_input& in) {
const int64_t remain = in.length() - in.file_pointer();
if (remain != format_utils::FOOTER_LEN) {
throw index_error(
std::string("while validating footer, error: invalid position '") + std::to_string(remain) + "'"
);
throw index_error(string_utils::to_string(
"while validating footer, error: invalid position '%ld'",
remain
));
}
const int32_t magic = in.read_int();
if (magic != format_utils::FOOTER_MAGIC) {
throw index_error(
std::string("while validating footer, error: invalid magic number '") + std::to_string(magic) + "'"
);
throw index_error(string_utils::to_string(
"while validating footer, error: invalid magic number '%d'",
magic
));
}
const int32_t alg_id = in.read_int();
if (alg_id != 0) {
throw index_error(
std::string("while validating footer, error: invalid algorithm '") + std::to_string(alg_id) + "'"
);
throw index_error(string_utils::to_string(
"while validating footer, error: invalid algorithm '%d'",
alg_id
));
}
}
@ -79,27 +80,28 @@ int32_t check_header(
const int32_t magic = in.read_int();
if (FORMAT_MAGIC != magic) {
throw irs::index_error(
std::string("while checking header, error: invalid magic '") + std::to_string(magic) + "'"
);
throw irs::index_error(string_utils::to_string(
"while checking header, error: invalid magic '%d'",
magic
));
}
const auto format = read_string<std::string>(in);
if (compare(req_format, format) != 0) {
std::stringstream ss;
ss << "while checking header, error: format mismatch '" << format << "' != '" << req_format << "'";
throw irs::index_error(ss.str());
throw irs::index_error(string_utils::to_string(
"while checking header, error: format mismatch '%s' != '%s'",
format.c_str(), req_format.c_str()
));
}
const int32_t ver = in.read_int();
if (ver < min_ver || ver > max_ver) {
throw irs::index_error(
std::string("while checking header, error: invalid version '") + std::to_string(ver) + "'"
);
throw irs::index_error(string_utils::to_string(
"while checking header, error: invalid version '%d'",
ver
));
}
return ver;
@ -107,4 +109,4 @@ int32_t check_header(
NS_END
NS_END
NS_END

View File

@ -25,6 +25,7 @@
#define IRESEARCH_FORMATS_UTILS_H
#include "store/store_utils.hpp"
#include "utils/string_utils.hpp"
#include "index/field_meta.hpp"
NS_ROOT
@ -81,9 +82,10 @@ inline int64_t check_footer(index_input& in, int64_t checksum) {
validate_footer(in);
if (checksum != in.read_long()) {
throw index_error(
std::string("while checking footer, error: invalid checksum '") + std::to_string(checksum) + "'"
);
throw index_error(string_utils::to_string(
"while checking footer, error: invalid checksum '" IR_UINT64_T_SPECIFIER "'",
checksum
));
}
return checksum;
@ -106,4 +108,4 @@ inline int64_t checksum(const index_input& in) {
NS_END
NS_END
#endif
#endif

View File

@ -215,11 +215,10 @@ inline void prepare_output(
out = state.dir->create(str);
if (!out) {
std::stringstream ss;
ss << "failed to create file, path: " << str;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to create file, path: %s",
str.c_str()
));
}
format_utils::write_header(*out, format, version);
@ -239,11 +238,10 @@ inline void prepare_input(
in = state.dir->open(str, advice);
if (!in) {
std::stringstream ss;
ss << "failed to open file, path: " << str;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to open file, path: %s",
str.c_str()
));
}
format_utils::check_header(*in, format, min_ver, max_ver);
@ -652,9 +650,10 @@ void postings_writer::begin_doc(doc_id_t id, const frequency* freq) {
}
if (id < doc.last) {
throw index_error(
std::string("while beginning doc in postings_writer, error: docs out of order '") + std::to_string(id) + "' < '" + std::to_string(doc.last) + "'"
);
throw index_error(string_utils::to_string(
"while beginning doc in postings_writer, error: docs out of order '%d' < '%d'",
id, doc.last
));
}
doc.doc(id - doc.last);
@ -1534,7 +1533,7 @@ class offs_pay_iterator final: public pos_iterator {
if (pay_lengths_[i]) {
const auto size = pay_lengths_[i]; // length of current payload
oversize(pay_data_, pos + size);
string_utils::oversize(pay_data_, pos + size);
#ifdef IRESEARCH_DEBUG
const auto read = pos_in_->read_bytes(&(pay_data_[0]) + pos, size);
@ -1561,7 +1560,7 @@ class offs_pay_iterator final: public pos_iterator {
const uint32_t size = pay_in_->read_vint();
if (size) {
format_traits::read_block(*pay_in_, postings_writer::BLOCK_SIZE, enc_buf_, pay_lengths_);
oversize(pay_data_, size);
string_utils::oversize(pay_data_, size);
#ifdef IRESEARCH_DEBUG
const auto read = pay_in_->read_bytes(&(pay_data_[0]), size);
@ -1789,7 +1788,7 @@ class pay_iterator final : public pos_iterator {
if (pay_lengths_[i]) {
const auto size = pay_lengths_[i]; // current payload length
oversize(pay_data_, pos + size);
string_utils::oversize(pay_data_, pos + size);
#ifdef IRESEARCH_DEBUG
const auto read = pos_in_->read_bytes(&(pay_data_[0]) + pos, size);
@ -1817,7 +1816,7 @@ class pay_iterator final : public pos_iterator {
const uint32_t size = pay_in_->read_vint();
if (size) {
format_traits::read_block(*pay_in_, postings_writer::BLOCK_SIZE, enc_buf_, pay_lengths_);
oversize(pay_data_, size);
string_utils::oversize(pay_data_, size);
#ifdef IRESEARCH_DEBUG
const auto read = pay_in_->read_bytes(&(pay_data_[0]), size);
@ -2041,11 +2040,10 @@ void index_meta_writer::commit() {
auto clear_pending = make_finally([this]{ meta_ = nullptr; });
if (!dir_->rename(src, dst)) {
std::stringstream ss;
ss << "failed to rename file, src path: " << src << " dst path: " << dst;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to rename file, src path: '%s' dst path: '%s'",
src.c_str(), dst.c_str()
));
}
complete(*meta_);
@ -2117,11 +2115,10 @@ void index_meta_reader::read(
);
if (!in) {
std::stringstream ss;
ss << "failed to open file, path: " << meta_file;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to open file, path: %s",
meta_file.c_str()
));
}
const auto checksum = format_utils::checksum(*in);
@ -2195,7 +2192,10 @@ void segment_meta_writer::write(directory& dir, const segment_meta& meta) {
byte_type flags = meta.column_store ? segment_meta_writer::flags_t::HAS_COLUMN_STORE : 0;
if (!out) {
throw detailed_io_error("failed to create file, path: " + meta_file);
throw detailed_io_error(string_utils::to_string(
"failed to create file, path: %s",
meta_file.c_str()
));
}
format_utils::write_header(*out, FORMAT_NAME, FORMAT_MAX);
@ -2235,11 +2235,10 @@ void segment_meta_reader::read(
);
if (!in) {
std::stringstream ss;
ss << "failed to open file, path: " << meta_file;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to open file, path: %s",
meta_file.c_str()
));
}
const auto checksum = format_utils::checksum(*in);
@ -2338,7 +2337,10 @@ void document_mask_writer::write(
auto out = dir.create(filename);
if (!out) {
throw detailed_io_error("Failed to create file, path: " + filename);
throw detailed_io_error(string_utils::to_string(
"Failed to create file, path: %s",
filename.c_str()
));
}
// segment can't have more than integer_traits<uint32_t>::const_max documents
@ -2664,7 +2666,7 @@ void read_compact(
return;
}
irs::oversize(encode_buf, buf_size);
irs::string_utils::oversize(encode_buf, buf_size);
#ifdef IRESEARCH_DEBUG
const auto read = in.read_bytes(&(encode_buf[0]), buf_size);
@ -2685,9 +2687,10 @@ void read_compact(
);
if (!irs::type_limits<iresearch::type_t::address_t>::valid(buf_size)) {
throw index_error(
std::string("while reading compact, error: invalid buffer size '") + std::to_string(buf_size) + "'"
);
throw irs::index_error(string_utils::to_string(
"while reading compact, error: invalid buffer size '" IR_SIZE_T_SPECIFIER "'",
buf_size
));
}
}
@ -5004,10 +5007,10 @@ bool postings_reader::prepare(
const uint64_t block_size = in.read_vint();
if (block_size != postings_writer::BLOCK_SIZE) {
throw index_error(
std::string("while preparing postings_reader in segment '") + state.meta->name
+ "', error: invalid block size '" + std::to_string(block_size) + "'"
);
throw index_error(string_utils::to_string(
"while preparing postings_reader, error: invalid block size '" IR_UINT64_T_SPECIFIER "'",
block_size
));
}
return true;
@ -5228,4 +5231,4 @@ NS_END // root
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -177,11 +177,10 @@ inline void prepare_output(
out = state.dir->create(str);
if (!out) {
std::stringstream ss;
ss << "failed to create file, path: " << str;
throw detailed_io_error(ss.str()) ;
throw detailed_io_error(string_utils::to_string(
"failed to create file, path: %s",
str.c_str()
));
}
format_utils::write_header(*out, format, version);
@ -203,11 +202,10 @@ inline void prepare_input(
in = state.dir->open(str, advice);
if (!in) {
std::stringstream ss;
ss << "failed to open file, path: " << str;
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to open file, path: %s",
str.c_str()
));
}
if (checksum) {
@ -1820,4 +1818,4 @@ NS_END /* root */
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -24,6 +24,7 @@
#include "composite_reader_impl.hpp"
#include "utils/directory_utils.hpp"
#include "utils/singleton.hpp"
#include "utils/string_utils.hpp"
#include "utils/type_limits.hpp"
#include "directory_reader.hpp"
@ -321,9 +322,10 @@ directory_reader_impl::directory_reader_impl(
}
if (!ctx.reader) {
throw index_error(
std::string("while opening reader for segment '") + segment.name + "', error: failed to open reader"
);
throw index_error(string_utils::to_string(
"while opening reader for segment '%s', error: failed to open reader",
segment.name.c_str()
));
}
ctx.base = static_cast<doc_id_t>(docs_max);
@ -356,4 +358,4 @@ NS_END
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -30,6 +30,7 @@
#include "utils/bitvector.hpp"
#include "utils/directory_utils.hpp"
#include "utils/index_utils.hpp"
#include "utils/string_utils.hpp"
#include "utils/timer_utils.hpp"
#include "utils/type_limits.hpp"
#include "utils/range.hpp"
@ -109,10 +110,10 @@ bool add_document_mask_modified_records(
auto reader = readers.emplace(meta);
if (!reader) {
throw irs::index_error(
std::string("while adding document mask modified records to document_mask of segment '") +meta.name
+ "', error: failed to open segment"
);
throw irs::index_error(irs::string_utils::to_string(
"while adding document mask modified records to document_mask of segment '%s', error: failed to open segment",
meta.name.c_str()
));
}
bool modified = false;
@ -164,10 +165,10 @@ bool add_document_mask_modified_records(
auto reader = readers.emplace(ctx.segment_.meta);
if (!reader) {
throw irs::index_error(
std::string("while adding document mask modified records to flush_segment_context of segment '") + ctx.segment_.meta.name
+ "', error: failed to open segment"
);
throw irs::index_error(irs::string_utils::to_string(
"while adding document mask modified records to flush_segment_context of segment '%s', error: failed to open segment",
ctx.segment_.meta.name.c_str()
));
}
assert(doc_limits::valid(ctx.doc_id_begin_));
@ -687,10 +688,10 @@ index_writer::flush_context_ptr index_writer::documents_context::update_segment(
);
if (!segment.flush()) {
throw index_error(
std::string("while flushing segment '") + segment.writer_meta_.meta.name
+ "', error: failed to flush segment"
);
throw index_error(string_utils::to_string(
"while flushing segment '%s', error: failed to flush segment",
segment.writer_meta_.meta.name.c_str()
));
}
}
@ -2060,7 +2061,10 @@ bool index_writer::start() {
auto sync = [&dir](const std::string& file) {
if (!dir.sync(file)) {
throw detailed_io_error("failed to sync file, path: " + file);
throw detailed_io_error(string_utils::to_string(
"failed to sync file, path: %s",
file.c_str()
));
}
return true;
@ -2152,4 +2156,4 @@ NS_END
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -24,6 +24,7 @@
#include "composite_reader_impl.hpp"
#include "search/bitset_doc_iterator.hpp"
#include "store/store_utils.hpp"
#include "utils/string_utils.hpp"
#include "transaction_store.hpp"
@ -1066,7 +1067,7 @@ store_reader store_reader::reopen() const {
void store_writer::bstring_output::ensure(size_t pos) {
if (pos >= buf_.size()) {
oversize(buf_, irs::math::roundup_power2(pos + 1)); // 2*size growth policy, +1 for offset->size
irs::string_utils::oversize(buf_, irs::math::roundup_power2(pos + 1)); // 2*size growth policy, +1 for offset->size
}
}

View File

@ -27,6 +27,7 @@
#include "error/error.hpp"
#include "utils/log.hpp"
#include "utils/object_pool.hpp"
#include "utils/string_utils.hpp"
#include "utils/utf8_path.hpp"
#include "utils/file_utils.hpp"
#include "utils/crc.hpp"
@ -37,8 +38,6 @@
#include <boost/locale/encoding.hpp>
#include <sstream>
NS_LOCAL
inline size_t buffer_size(FILE* file) NOEXCEPT {
@ -225,11 +224,10 @@ class fs_index_output : public buffered_index_output {
crc.process_bytes(b, len_written);
if (len && len_written != len) {
std::stringstream ss;
ss << "failed to write buffer, written '" << len_written << "' out of '" << len << "' bytes";
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to write buffer, written '" IR_SIZE_T_SPECIFIER "' out of '" IR_SIZE_T_SPECIFIER "' bytes",
len_written, len
));
}
}
@ -332,11 +330,10 @@ class fs_index_input : public buffered_index_input {
protected:
virtual void seek_internal(size_t pos) override {
if (pos >= handle_->size) {
std::stringstream ss;
ss << "seek out of range for input file, length '" << handle_->size << "', position '" << pos << "'";
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"seek out of range for input file, length '" IR_SIZE_T_SPECIFIER "', position '" IR_SIZE_T_SPECIFIER "'",
handle_->size, pos
));
}
pos_ = pos;
@ -350,11 +347,10 @@ class fs_index_input : public buffered_index_input {
if (handle_->pos != pos_) {
if (fseek(stream, static_cast<long>(pos_), SEEK_SET) != 0) {
std::stringstream ss;
ss << "failed to seek to '" << pos_ << "' for input file, error '" << ferror(stream) << "'";
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to seek to '" IR_SIZE_T_SPECIFIER "' for input file, error '%d'",
pos_, ferror(stream)
));
}
handle_->pos = pos_;
@ -371,11 +367,10 @@ class fs_index_input : public buffered_index_input {
}
// read error
std::stringstream ss;
ss << "failed to read from input file, read '" << read << "' out of '" << len << "' bytes, error '" << ferror(stream) << "'";
throw detailed_io_error(ss.str());
throw detailed_io_error(string_utils::to_string(
"failed to read from input file, read '" IR_SIZE_T_SPECIFIER "' out of '" IR_SIZE_T_SPECIFIER "' bytes, error '%d'",
read, len, ferror(stream)
));
}
assert(handle_->pos == pos_);
@ -684,4 +679,4 @@ NS_END
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -26,6 +26,7 @@
#include "utils/crc.hpp"
#include "utils/std.hpp"
#include "utils/string_utils.hpp"
#include "utils/memory.hpp"
NS_ROOT
@ -423,7 +424,7 @@ void bytes_input::read_from(data_input& in, size_t size) {
return;
}
oversize(buf_, size);
string_utils::oversize(buf_, size);
#ifdef IRESEARCH_DEBUG
const auto read = in.read_bytes(&(buf_[0]), size);

View File

@ -24,6 +24,7 @@
#include "shared.hpp"
#include "error/error.hpp"
#include "compression.hpp"
#include "utils/string_utils.hpp"
#include "utils/type_limits.hpp"
#include <lz4.h>
@ -33,7 +34,7 @@ NS_ROOT
compressor::compressor(unsigned int chunk_size):
dict_size_(0),
stream_(LZ4_createStream(), [](void* ptr)->void { LZ4_freeStream(reinterpret_cast<LZ4_stream_t*>(ptr)); }) {
oversize(buf_, LZ4_COMPRESSBOUND(chunk_size));
string_utils::oversize(buf_, LZ4_COMPRESSBOUND(chunk_size));
}
void compressor::compress(const char* src, size_t size) {
@ -51,7 +52,7 @@ void compressor::compress(const char* src, size_t size) {
assert(dict_size_ >= 0);
}
oversize(buf_, LZ4_compressBound(src_size) + dict_size_);
string_utils::oversize(buf_, LZ4_compressBound(src_size) + dict_size_);
// reload the LZ4 dictionary if buf_ has changed
if (&(buf_[0]) != dict_store) {

View File

@ -255,8 +255,8 @@ NS_END
// -----------------------------------------------------------------------------
tracking_directory::tracking_directory(
directory& impl, bool track_open /*= false*/):
impl_(impl), track_open_(track_open) {
directory& impl, bool track_open /*= false*/
) : impl_(impl), track_open_(track_open) {
}
tracking_directory::~tracking_directory() {}
@ -403,15 +403,15 @@ bool tracking_directory::sync(const std::string& name) NOEXCEPT {
// -----------------------------------------------------------------------------
ref_tracking_directory::ref_tracking_directory(
directory& impl, bool track_open /*= false*/
):
attribute_(impl.attributes().emplace<index_file_refs>()),
directory& impl,
bool track_open /*= false*/
) : attribute_(impl.attributes().emplace<index_file_refs>()),
impl_(impl),
track_open_(track_open) {
}
ref_tracking_directory::ref_tracking_directory(
ref_tracking_directory&& other
ref_tracking_directory&& other
) NOEXCEPT
: attribute_(other.attribute_), // references do not require std::move(...)
impl_(other.impl_), // references do not require std::move(...)
@ -449,7 +449,7 @@ index_output::ptr ref_tracking_directory::create(
auto ref = attribute_->add(name);
SCOPED_LOCK(mutex_);
refs_.emplace(*ref, std::move(ref));
refs_.emplace(ref);
}
return result;
@ -500,7 +500,7 @@ index_input::ptr ref_tracking_directory::open(
auto ref = attribute_->add(name);
SCOPED_LOCK(mutex_);
refs_.emplace(*ref, std::move(ref));
refs_.emplace(ref);
} catch (...) {
IR_LOG_EXCEPTION();
@ -519,9 +519,15 @@ bool ref_tracking_directory::remove(const std::string& name) NOEXCEPT {
try {
attribute_->remove(name);
// aliasing ctor
const index_file_refs::ref_t ref(
index_file_refs::ref_t(),
&name
);
SCOPED_LOCK(mutex_);
refs_.erase(name);
refs_.erase(ref);
return true;
} catch (...) {
IR_LOG_EXCEPTION();
@ -542,10 +548,16 @@ bool ref_tracking_directory::rename(
auto ref = attribute_->add(dst);
{
// aliasing ctor
const index_file_refs::ref_t src_ref(
index_file_refs::ref_t(),
&src
);
SCOPED_LOCK(mutex_);
refs_.emplace(dst, ref);
refs_.erase(src);
refs_.emplace(ref);
refs_.erase(src_ref);
}
attribute_->remove(src);
@ -571,7 +583,7 @@ bool ref_tracking_directory::visit_refs(
SCOPED_LOCK(mutex_);
for (const auto& ref: refs_) {
if (!visitor(ref.second)) {
if (!visitor(ref)) {
return false;
}
}

View File

@ -108,7 +108,7 @@ struct IRESEARCH_API tracking_directory: public directory {
typedef std::unordered_set<std::string> file_set;
// @param track_open - track file refs for calls to open(...)
tracking_directory(directory& impl, bool track_open = false);
explicit tracking_directory(directory& impl, bool track_open = false);
virtual ~tracking_directory();
directory& operator*() NOEXCEPT;
using directory::attributes;
@ -155,7 +155,7 @@ struct IRESEARCH_API ref_tracking_directory: public directory {
public:
DECLARE_UNIQUE_PTR(ref_tracking_directory);
// @param track_open - track file refs for calls to open(...)
ref_tracking_directory(directory& impl, bool track_open = false);
explicit ref_tracking_directory(directory& impl, bool track_open = false);
ref_tracking_directory(ref_tracking_directory&& other) NOEXCEPT;
virtual ~ref_tracking_directory();
directory& operator*() NOEXCEPT;
@ -185,11 +185,17 @@ struct IRESEARCH_API ref_tracking_directory: public directory {
bool visit_refs(const std::function<bool(const index_file_refs::ref_t& ref)>& visitor) const;
private:
typedef std::unordered_set<
index_file_refs::ref_t,
index_file_refs::counter_t::hash,
index_file_refs::counter_t::equal_to
> refs_t;
IRESEARCH_API_PRIVATE_VARIABLES_BEGIN
index_file_refs::attribute_t& attribute_;
directory& impl_;
mutable std::mutex mutex_; // for use with refs_
mutable std::unordered_map<string_ref, index_file_refs::ref_t> refs_;
mutable refs_t refs_;
bool track_open_;
IRESEARCH_API_PRIVATE_VARIABLES_END
};

View File

@ -2676,7 +2676,9 @@ typename num_put_facet<CharType, CvtType>::iter_type num_put_facet<CharType, Cvt
auto ctx = context();
if (!ctx) {
throw irs::detailed_io_error("failed to retrieve ICU formatter in num_put_facet::do_put(...)");
throw irs::detailed_io_error(
"failed to retrieve ICU formatter in num_put_facet::do_put(...)"
);
}
static_assert(sizeof(int64_t) == sizeof(long long), "sizeof(int64_t) != sizeof(long long)");
@ -3771,4 +3773,4 @@ NS_END
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

View File

@ -26,7 +26,7 @@
#include <functional>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include "shared.hpp"
#include "utils/noncopyable.hpp"
@ -40,37 +40,59 @@ class ref_counter : public util::noncopyable { // noncopyable because shared_ptr
public:
typedef std::shared_ptr<const Key> ref_t;
struct equal_to : Equal {
bool operator()(const ref_t& lhs, const ref_t& rhs) const {
assert(lhs && rhs);
return Equal::operator()(*lhs, *rhs);
}
}; // equal_to
struct hash : Hash {
bool operator()(const ref_t& value) const {
assert(value);
return Hash::operator()(*value);
}
}; // hash
ref_t add(Key&& key) {
SCOPED_LOCK(lock_);
auto itr = refs_.emplace(
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(nullptr)
);
auto res = refs_.emplace(ref_t(), &key);
if (itr.second) {
itr.first->second.reset(&(itr.first->first), memory::noop_deleter());
if (res.second) {
try {
const_cast<ref_t&>(*res.first) = std::make_shared<const Key>(std::forward<Key>(key));
} catch (...) {
// rollback
refs_.erase(res.first);
return ref_t();
}
}
return itr.first->second;
return *res.first;
}
bool remove(const Key& key) {
const ref_t ref(ref_t(), &key); // aliasing ctor
SCOPED_LOCK(lock_);
return refs_.erase(key) > 0;
return refs_.erase(ref) > 0;
}
bool contains(const Key& key) const NOEXCEPT {
const ref_t ref(ref_t(), &key); // aliasing ctor
SCOPED_LOCK(lock_);
return refs_.find(key) != refs_.end();
return refs_.find(ref) != refs_.end();
}
size_t find(const Key& key) const NOEXCEPT {
SCOPED_LOCK(lock_);
auto itr = refs_.find(key);
const ref_t ref(ref_t(), &key); // aliasing ctor
return itr == refs_.end() ? 0 : (itr->second.use_count() - 1); // -1 for usage by refs_ itself
SCOPED_LOCK(lock_);
auto itr = refs_.find(ref);
return itr == refs_.end() ? 0 : (itr->use_count() - 1); // -1 for usage by refs_ itself
}
bool empty() const NOEXCEPT {
@ -83,9 +105,12 @@ class ref_counter : public util::noncopyable { // noncopyable because shared_ptr
SCOPED_LOCK(lock_);
for (auto itr = refs_.begin(), end = refs_.end(); itr != end;) {
auto visit_next = visitor(itr->first, itr->second.use_count() - 1); // -1 for usage by refs_ itself
auto& ref = *itr;
assert(*itr);
if (remove_unused && itr->second.unique()) {
auto visit_next = visitor(*ref, ref.use_count() - 1); // -1 for usage by refs_ itself
if (remove_unused && ref.unique()) {
itr = refs_.erase(itr);
} else {
++itr;
@ -101,7 +126,7 @@ class ref_counter : public util::noncopyable { // noncopyable because shared_ptr
private:
mutable std::recursive_mutex lock_; // recursive to allow usage for 'this' from withing visit(...)
std::unordered_map<Key, ref_t, Hash, Equal> refs_;
std::unordered_set<ref_t, hash, equal_to> refs_;
}; // ref_counter
NS_END

View File

@ -129,17 +129,6 @@ NS_ROOT
typedef std::basic_string<byte_type> bstring;
template<typename T>
inline std::basic_string<T>& oversize(
// 31 == 32 - 1: because std::basic_string reserves a \0 at the end
// 32 is the original default value used in bytes_builder
std::basic_string<T>& buf, size_t size = 31
) {
buf.resize(size);
buf.resize(buf.capacity()); // use up the entire buffer
return buf;
}
//////////////////////////////////////////////////////////////////////////////
/// @class basic_string_ref
//////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,96 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
#ifndef IRESEARCH_STRING_UTILS_H
#define IRESEARCH_STRING_UTILS_H
#include "shared.hpp"
NS_ROOT
NS_BEGIN(string_utils)
////////////////////////////////////////////////////////////////////////////////
/// @brief resize string to the full capacity of resize to the specified size
////////////////////////////////////////////////////////////////////////////////
template<typename T>
inline std::basic_string<T>& oversize(
// 31 == 32 - 1: because std::basic_string reserves a \0 at the end
// 32 is the original default value used in bytes_builder
std::basic_string<T>& buf, size_t size = 31
) {
buf.resize(size);
buf.resize(buf.capacity()); // use up the entire buffer
return buf;
}
////////////////////////////////////////////////////////////////////////////////
/// @param destination buffer
/// @return as per sprintf(...)
////////////////////////////////////////////////////////////////////////////////
template <typename... Args>
inline int to_string(std::string& buf, const char* format, Args&&... args) {
char ch;
auto result = snprintf(&ch, 0, format, std::forward<Args>(args)...);
if (result <= 0) {
return result;
}
auto start = buf.size();
++result; // +1 because snprintf(...) requires space for '\0'
buf.resize(buf.size() + result);
try {
result = snprintf(&buf[start], result, format, std::forward<Args>(args)...);
buf.resize(start + std::max(0, result));
} catch (...) {
buf.resize(start);
throw;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @return formatted string
/// @note asserts on failure
////////////////////////////////////////////////////////////////////////////////
template <typename... Args>
inline std::string to_string(const char* format, Args&&... args) {
std::string buf;
const auto result = to_string(buf, format, std::forward<Args>(args)...);
assert(result >= 0);
assert(size_t(result) == buf.size());
UNUSED(result);
return buf;
}
NS_END // string_utils
NS_END
#endif

View File

@ -23,6 +23,7 @@
#include "tests_shared.hpp"
#include "utils/string.hpp"
#include "utils/string_utils.hpp"
#include "utils/block_pool.hpp"
#include "utils/misc.hpp"
@ -124,7 +125,7 @@ class block_pool_test : public test_base {
if (i % 3 == 0) { // read data within slice
bstring payload;
size_t size = r.read(&(oversize(payload, slice_data.size())[0]), slice_data.size());
size_t size = r.read(&(string_utils::oversize(payload, slice_data.size())[0]), slice_data.size());
EXPECT_TRUE(slice_data.size() == size);
EXPECT_TRUE(memcmp(slice_data.c_str(), payload.data(), std::min(slice_data.size(), size)) == 0);
}

View File

@ -23,6 +23,7 @@
#include "gtest/gtest.h"
#include "utils/ref_counter.hpp"
#include <unordered_map>
namespace tests {
class ref_counter_tests: public ::testing::Test {