mirror of https://gitee.com/bigwinds/arangodb
* fix recovery * update iresearch * more fixes * address review comments
This commit is contained in:
parent
54169cd44f
commit
595728ec1b
|
@ -556,29 +556,36 @@ if(MSVC)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
unset(IResearch_STATIC_LIBRARIES)
|
||||
unset(IResearch_STATIC_LIBRARIES)
|
||||
|
||||
set(IRESEARCH_STATIC_DEPENDENCIES
|
||||
${BFD_STATIC_LIBS}
|
||||
${Unwind_STATIC_LIBS}
|
||||
"$<TARGET_FILE:icudata-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icui18n-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icuuc-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:lz4_static>"
|
||||
"$<TARGET_FILE:stemmer-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-delimiter-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-ngram-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-text-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-norm-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-stem-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-mask-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-format-1_0-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-tfidf-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-bm25-static>"
|
||||
)
|
||||
|
||||
if (USE_SIMDCOMP)
|
||||
list(APPEND IRESEARCH_STATIC_DEPENDENCIES "$<TARGET_FILE:${SIMD_LIBRARY_STATIC}>")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
foreach(ELEMENT
|
||||
${BFD_STATIC_LIBS}
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
${Unwind_STATIC_LIBS}
|
||||
"$<TARGET_FILE:icudata-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icui18n-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icuuc-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:lz4_static>"
|
||||
"$<TARGET_FILE:stemmer-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-delimiter-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-ngram-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-text-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-norm-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-stem-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-mask-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-format-1_0-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-tfidf-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-bm25-static>"
|
||||
)
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
${IRESEARCH_STATIC_DEPENDENCIES})
|
||||
set(IResearch_STATIC_LIBRARIES "${IResearch_STATIC_LIBRARIES} \"${ELEMENT}\"")
|
||||
endforeach()
|
||||
|
||||
|
@ -621,25 +628,9 @@ if (MSVC)
|
|||
unset(IResearch_STATIC_SCRT_LIBRARIES)
|
||||
|
||||
foreach(ELEMENT
|
||||
${BFD_STATIC_LIBS}
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_staticRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_staticRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_staticRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_staticRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
${Unwind_STATIC_LIBS}
|
||||
"$<TARGET_FILE:icudata-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icui18n-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icuuc-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:lz4_static>"
|
||||
"$<TARGET_FILE:stemmer-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-delimiter-static-scrt>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-ngram-static-scrt>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-text-static-scrt>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-norm-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-stem-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-mask-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-format-1_0-static-scrt>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-tfidf-static-scrt>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-bm25-static-scrt>"
|
||||
)
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_staticRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_staticRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_staticRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_staticRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
${IRESEARCH_STATIC_DEPENDENCIES})
|
||||
set(IResearch_STATIC_SCRT_LIBRARIES "${IResearch_STATIC_SCRT_LIBRARIES} \"${ELEMENT}\"")
|
||||
endforeach()
|
||||
|
||||
|
@ -679,29 +670,11 @@ if (MSVC)
|
|||
${IResearch_TARGET_NAME}-static-scrt-allinone-build
|
||||
)
|
||||
elseif (APPLE)
|
||||
unset(IResearch_STATIC_LIBRARIES)
|
||||
|
||||
foreach(ELEMENT
|
||||
${BFD_STATIC_LIBS}
|
||||
${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}
|
||||
${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}
|
||||
${Boost_STATIC_sharedRT_THREAD_LIBRARY_DEBUG}
|
||||
${Unwind_STATIC_LIBS}
|
||||
"$<TARGET_FILE:icudata-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icui18n-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icuuc-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:lz4_static>"
|
||||
"$<TARGET_FILE:stemmer-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-delimiter-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-ngram-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-text-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-norm-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-stem-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-mask-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-format-1_0-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-tfidf-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-bm25-static>"
|
||||
)
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_THREAD_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_THREAD_LIBRARY_RELEASE}>"
|
||||
${IRESEARCH_STATIC_DEPENDENCIES})
|
||||
set(IResearch_STATIC_LIBRARIES "${IResearch_STATIC_LIBRARIES} '${ELEMENT}'")
|
||||
endforeach ()
|
||||
|
||||
|
@ -740,33 +713,15 @@ elseif (APPLE)
|
|||
${IResearch_TARGET_NAME}-static-allinone-build
|
||||
)
|
||||
else()
|
||||
unset(IResearch_STATIC_LIBRARIES)
|
||||
|
||||
foreach(ELEMENT
|
||||
${BFD_STATIC_LIBS}
|
||||
${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}
|
||||
${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}
|
||||
${Boost_STATIC_sharedRT_THREAD_LIBRARY_DEBUG}
|
||||
${Unwind_STATIC_LIBS}
|
||||
"$<TARGET_FILE:icudata-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icui18n-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:icuuc-static>" # must expand icu-static into components
|
||||
"$<TARGET_FILE:lz4_static>"
|
||||
"$<TARGET_FILE:stemmer-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-delimiter-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-ngram-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-text-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-norm-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-stem-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-analyzer-mask-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-format-1_0-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-tfidf-static>"
|
||||
"$<TARGET_FILE:${IResearch_TARGET_NAME}-scorer-bm25-static>"
|
||||
)
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_LOCALE_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_SYSTEM_LIBRARY_RELEASE}>"
|
||||
"$<$<CONFIG:Debug>:${Boost_STATIC_sharedRT_THREAD_LIBRARY_DEBUG}>$<$<NOT:$<CONFIG:Debug>>:${Boost_STATIC_sharedRT_THREAD_LIBRARY_RELEASE}>"
|
||||
${IRESEARCH_STATIC_DEPENDENCIES})
|
||||
set(IResearch_STATIC_LIBRARIES "${IResearch_STATIC_LIBRARIES} addlib '${ELEMENT}'\\n")
|
||||
endforeach ()
|
||||
|
||||
set(IResearch_STATIC_LIBRARIES_OUT "${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/libresearch-sa${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
set(IResearch_STATIC_LIBRARIES_OUT "${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/libiresearch-sa${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
set(IResearch_STATIC_LIBRARIES_CMD "`which echo` -e \"create '${IResearch_STATIC_LIBRARIES_OUT}'\\n addlib '$<TARGET_FILE:${IResearch_TARGET_NAME}-static>'\\n ${IResearch_STATIC_LIBRARIES} save\\n end\" | ar -M")
|
||||
add_custom_command(
|
||||
OUTPUT "${IResearch_STATIC_LIBRARIES_OUT}"
|
||||
|
|
|
@ -82,12 +82,18 @@ DEFINE_ATTRIBUTE_TYPE(iresearch::term_meta)
|
|||
index_meta& meta,
|
||||
uint64_t generation,
|
||||
uint64_t counter,
|
||||
index_meta::index_segments_t&& segments
|
||||
index_meta::index_segments_t&& segments,
|
||||
bstring* payload
|
||||
) {
|
||||
meta.gen_ = generation;
|
||||
meta.last_gen_ = generation;
|
||||
meta.seg_counter_ = counter;
|
||||
meta.segments_ = std::move(segments);
|
||||
if (payload) {
|
||||
meta.payload(std::move(*payload));
|
||||
} else {
|
||||
meta.payload(bytes_ref::NIL);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ bool formats::exists(
|
||||
|
|
|
@ -447,7 +447,8 @@ struct IRESEARCH_API index_meta_reader {
|
|||
index_meta& meta,
|
||||
uint64_t generation,
|
||||
uint64_t counter,
|
||||
index_meta::index_segments_t&& segments
|
||||
index_meta::index_segments_t&& segments,
|
||||
bstring* payload_buf
|
||||
);
|
||||
}; // index_meta_reader
|
||||
|
||||
|
|
|
@ -1041,8 +1041,24 @@ class doc_iterator : public irs::doc_iterator {
|
|||
|
||||
seek_to_block(target);
|
||||
|
||||
// FIXME binary search instead of linear
|
||||
while ((doc_.value < target) && next());
|
||||
if (begin_ == end_) {
|
||||
cur_pos_ += relative_pos();
|
||||
|
||||
if (cur_pos_ == term_state_.docs_count) {
|
||||
doc_.value = doc_limits::eof();
|
||||
begin_ = end_ = docs_; // seal the iterator
|
||||
return doc_limits::eof();
|
||||
}
|
||||
|
||||
refill();
|
||||
}
|
||||
|
||||
while (begin_ < end_ && *begin_ < target) {
|
||||
++begin_;
|
||||
}
|
||||
doc_freq_ = doc_freqs_ + relative_pos();
|
||||
|
||||
next();
|
||||
return doc_.value;
|
||||
}
|
||||
|
||||
|
@ -1879,6 +1895,34 @@ class pay_iterator final : public pos_iterator {
|
|||
template<typename PosItrType>
|
||||
class pos_doc_iterator final: public doc_iterator {
|
||||
public:
|
||||
virtual doc_id_t seek(doc_id_t target) override {
|
||||
if (target <= doc_.value) {
|
||||
return doc_.value;
|
||||
}
|
||||
|
||||
seek_to_block(target);
|
||||
|
||||
if (begin_ == end_) {
|
||||
cur_pos_ += relative_pos();
|
||||
|
||||
if (cur_pos_ == term_state_.docs_count) {
|
||||
doc_.value = doc_limits::eof();
|
||||
begin_ = end_ = docs_; // seal the iterator
|
||||
return doc_limits::eof();
|
||||
}
|
||||
|
||||
refill();
|
||||
}
|
||||
|
||||
while (begin_ < end_ && *begin_ < target) {
|
||||
++begin_;
|
||||
pos_.pend_pos_ += *doc_freq_++;
|
||||
}
|
||||
|
||||
next();
|
||||
return doc_.value;
|
||||
}
|
||||
|
||||
virtual bool next() override {
|
||||
if (begin_ == end_) {
|
||||
cur_pos_ += relative_pos();
|
||||
|
@ -1967,16 +2011,25 @@ struct index_meta_writer final: public irs::index_meta_writer {
|
|||
static const string_ref FORMAT_PREFIX_TMP;
|
||||
|
||||
static const int32_t FORMAT_MIN = 0;
|
||||
static const int32_t FORMAT_MAX = FORMAT_MIN;
|
||||
static const int32_t FORMAT_MAX = 1;
|
||||
|
||||
enum { HAS_PAYLOAD = 1 };
|
||||
|
||||
explicit index_meta_writer(int32_t version) NOEXCEPT
|
||||
: version_(version) {
|
||||
assert(version_ >= FORMAT_MIN && version <= FORMAT_MAX);
|
||||
}
|
||||
|
||||
virtual std::string filename(const index_meta& meta) const override;
|
||||
using irs::index_meta_writer::prepare;
|
||||
virtual bool prepare(directory& dir, index_meta& meta) override;
|
||||
virtual bool commit() override;
|
||||
virtual void rollback() NOEXCEPT override;
|
||||
|
||||
private:
|
||||
directory* dir_ = nullptr;
|
||||
index_meta* meta_ = nullptr;
|
||||
int32_t version_;
|
||||
}; // index_meta_writer
|
||||
|
||||
template<>
|
||||
|
@ -2032,7 +2085,7 @@ bool index_meta_writer::prepare(directory& dir, index_meta& meta) {
|
|||
}
|
||||
|
||||
{
|
||||
format_utils::write_header(*out, FORMAT_NAME, FORMAT_MAX);
|
||||
format_utils::write_header(*out, FORMAT_NAME, version_);
|
||||
out->write_vlong(meta.generation());
|
||||
out->write_long(meta.counter());
|
||||
assert(meta.size() <= integer_traits<uint32_t>::const_max);
|
||||
|
@ -2043,6 +2096,15 @@ bool index_meta_writer::prepare(directory& dir, index_meta& meta) {
|
|||
write_string(*out, segment.meta.codec->type().name());
|
||||
}
|
||||
|
||||
if (version_ > FORMAT_MIN) {
|
||||
const byte_type flags = meta.payload().null() ? 0 : HAS_PAYLOAD;
|
||||
out->write_byte(flags);
|
||||
|
||||
if (flags == HAS_PAYLOAD) {
|
||||
irs::write_string(*out, meta.payload());
|
||||
}
|
||||
}
|
||||
|
||||
format_utils::write_footer(*out);
|
||||
// important to close output here
|
||||
}
|
||||
|
@ -2170,7 +2232,7 @@ void index_meta_reader::read(
|
|||
const auto checksum = format_utils::checksum(*in);
|
||||
|
||||
// check header
|
||||
format_utils::check_header(
|
||||
const int32_t version = format_utils::check_header(
|
||||
*in,
|
||||
index_meta_writer::FORMAT_NAME,
|
||||
index_meta_writer::FORMAT_MIN,
|
||||
|
@ -2194,8 +2256,23 @@ void index_meta_reader::read(
|
|||
reader->read(dir, segment.meta, segment.filename);
|
||||
}
|
||||
|
||||
bool has_payload = false;
|
||||
bstring payload;
|
||||
if (version > index_meta_writer::FORMAT_MIN) {
|
||||
has_payload = (in->read_byte() & index_meta_writer::HAS_PAYLOAD);
|
||||
|
||||
if (has_payload) {
|
||||
payload = irs::read_string<bstring>(*in);
|
||||
}
|
||||
}
|
||||
|
||||
format_utils::check_footer(*in, checksum);
|
||||
complete(meta, gen, cnt, std::move(segments));
|
||||
|
||||
complete(
|
||||
meta, gen, cnt,
|
||||
std::move(segments),
|
||||
has_payload ? &payload : nullptr
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -2216,6 +2293,7 @@ struct segment_meta_writer final : public irs::segment_meta_writer{
|
|||
|
||||
explicit segment_meta_writer(int32_t version) NOEXCEPT
|
||||
: version_(version) {
|
||||
assert(version_ >= FORMAT_MIN && version <= FORMAT_MAX);
|
||||
}
|
||||
|
||||
virtual void write(
|
||||
|
@ -5207,7 +5285,7 @@ class format10 : public irs::version10::format {
|
|||
|
||||
format10() NOEXCEPT : format10(format10::type()) { }
|
||||
|
||||
virtual index_meta_writer::ptr get_index_meta_writer() const override final;
|
||||
virtual index_meta_writer::ptr get_index_meta_writer() const override;
|
||||
virtual index_meta_reader::ptr get_index_meta_reader() const override final;
|
||||
|
||||
virtual segment_meta_writer::ptr get_segment_meta_writer() const override;
|
||||
|
@ -5235,7 +5313,9 @@ class format10 : public irs::version10::format {
|
|||
}; // format10
|
||||
|
||||
index_meta_writer::ptr format10::get_index_meta_writer() const {
|
||||
return irs::index_meta_writer::make<::index_meta_writer>();
|
||||
return irs::index_meta_writer::make<::index_meta_writer>(
|
||||
int32_t(::index_meta_writer::FORMAT_MIN)
|
||||
);
|
||||
}
|
||||
|
||||
index_meta_reader::ptr format10::get_index_meta_reader() const {
|
||||
|
@ -5334,6 +5414,8 @@ class format11 final : public format10 {
|
|||
|
||||
format11() NOEXCEPT : format10(format11::type()) { }
|
||||
|
||||
virtual index_meta_writer::ptr get_index_meta_writer() const override final;
|
||||
|
||||
virtual field_writer::ptr get_field_writer(bool volatile_state) const override final;
|
||||
|
||||
virtual segment_meta_writer::ptr get_segment_meta_writer() const override final;
|
||||
|
@ -5341,6 +5423,12 @@ class format11 final : public format10 {
|
|||
virtual column_meta_writer::ptr get_column_meta_writer() const override final;
|
||||
}; // format10
|
||||
|
||||
index_meta_writer::ptr format11::get_index_meta_writer() const {
|
||||
return irs::index_meta_writer::make<::index_meta_writer>(
|
||||
int32_t(::index_meta_writer::FORMAT_MAX)
|
||||
);
|
||||
}
|
||||
|
||||
field_writer::ptr format11::get_field_writer(bool volatile_state) const {
|
||||
return irs::field_writer::make<burst_trie::field_writer>(
|
||||
get_postings_writer(volatile_state),
|
||||
|
|
|
@ -127,14 +127,18 @@ index_meta::index_meta(const index_meta& rhs)
|
|||
: gen_(rhs.gen_),
|
||||
last_gen_(rhs.last_gen_),
|
||||
seg_counter_(rhs.seg_counter_.load()),
|
||||
segments_(rhs.segments_) {
|
||||
segments_(rhs.segments_),
|
||||
payload_buf_(rhs.payload_buf_),
|
||||
payload_(rhs.payload_.null() ? bytes_ref::NIL : bytes_ref(payload_buf_)) {
|
||||
}
|
||||
|
||||
index_meta::index_meta(index_meta&& rhs) NOEXCEPT
|
||||
: gen_(std::move(rhs.gen_)),
|
||||
last_gen_(std::move(rhs.last_gen_)),
|
||||
seg_counter_(rhs.seg_counter_.load()),
|
||||
segments_(std::move(rhs.segments_)) {
|
||||
segments_(std::move(rhs.segments_)),
|
||||
payload_buf_(std::move(rhs.payload_buf_)),
|
||||
payload_(rhs.payload_.null() ? bytes_ref::NIL : bytes_ref(payload_buf_)) {
|
||||
}
|
||||
|
||||
index_meta& index_meta::operator=(index_meta&& rhs) NOEXCEPT {
|
||||
|
@ -143,6 +147,8 @@ index_meta& index_meta::operator=(index_meta&& rhs) NOEXCEPT {
|
|||
last_gen_ = std::move(rhs.last_gen_);
|
||||
seg_counter_ = rhs.seg_counter_.load();
|
||||
segments_ = std::move(rhs.segments_);
|
||||
payload_buf_ = std::move(rhs.payload_buf_);
|
||||
payload_ = rhs.payload_.null() ? bytes_ref::NIL : bytes_ref(payload_buf_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
@ -156,7 +162,8 @@ bool index_meta::operator==(const index_meta& other) const NOEXCEPT {
|
|||
if (gen_ != other.gen_
|
||||
|| last_gen_ != other.last_gen_
|
||||
|| seg_counter_ != other.seg_counter_
|
||||
|| segments_.size() != other.segments_.size()) {
|
||||
|| segments_.size() != other.segments_.size()
|
||||
|| payload_ != other.payload_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,9 @@ class IRESEARCH_API index_meta {
|
|||
index_meta& operator=(const index_meta&) = delete;
|
||||
|
||||
bool operator==(const index_meta& other) const NOEXCEPT;
|
||||
bool operator!=(const index_meta& other) const NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template<typename ForwardIterator>
|
||||
void add(ForwardIterator begin, ForwardIterator end) {
|
||||
|
@ -177,8 +180,8 @@ class IRESEARCH_API index_meta {
|
|||
last_gen_ = rhs.last_gen_;
|
||||
}
|
||||
|
||||
size_t size() const { return segments_.size(); }
|
||||
bool empty() const { return segments_.empty(); }
|
||||
size_t size() const NOEXCEPT { return segments_.size(); }
|
||||
bool empty() const NOEXCEPT { return segments_.empty(); }
|
||||
|
||||
void clear() {
|
||||
segments_.clear();
|
||||
|
@ -194,14 +197,20 @@ class IRESEARCH_API index_meta {
|
|||
assert(i < segments_.size());
|
||||
return segments_[i];
|
||||
}
|
||||
|
||||
const index_segment_t& operator[](size_t i) const NOEXCEPT {
|
||||
assert(i < segments_.size());
|
||||
return segments_[i];
|
||||
}
|
||||
|
||||
const index_segments_t& segments() const NOEXCEPT {
|
||||
return segments_;
|
||||
}
|
||||
|
||||
const bytes_ref& payload() const NOEXCEPT {
|
||||
return payload_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class index_writer;
|
||||
friend struct index_meta_reader;
|
||||
|
@ -212,9 +221,26 @@ class IRESEARCH_API index_meta {
|
|||
uint64_t last_gen_;
|
||||
std::atomic<uint64_t> seg_counter_;
|
||||
index_segments_t segments_;
|
||||
bstring payload_buf_;
|
||||
bytes_ref payload_;
|
||||
IRESEARCH_API_PRIVATE_VARIABLES_END
|
||||
|
||||
uint64_t next_generation() const NOEXCEPT;
|
||||
|
||||
void payload(bstring&& payload) NOEXCEPT {
|
||||
payload_buf_ = std::move(payload);
|
||||
payload_ = payload_buf_;
|
||||
}
|
||||
|
||||
void payload(const bytes_ref& payload) {
|
||||
if (payload.null()) {
|
||||
payload_buf_.clear();
|
||||
payload_ = bytes_ref::NIL;
|
||||
} else {
|
||||
payload_buf_ = payload;
|
||||
payload_ = payload_buf_;
|
||||
}
|
||||
}
|
||||
}; // index_meta
|
||||
|
||||
NS_END
|
||||
|
|
|
@ -1811,7 +1811,7 @@ index_writer::active_segment_context index_writer::get_segment_context(
|
|||
return active_segment_context(segment_ctx, segments_active_);
|
||||
}
|
||||
|
||||
index_writer::pending_context_t index_writer::flush_all() {
|
||||
index_writer::pending_context_t index_writer::flush_all(const bytes_ref& payload) {
|
||||
REGISTER_TIMER_DETAILED();
|
||||
bool modified = !type_limits<type_t::index_gen_t>::valid(meta_.last_gen_);
|
||||
sync_context to_sync;
|
||||
|
@ -2240,13 +2240,19 @@ index_writer::pending_context_t index_writer::flush_all() {
|
|||
|
||||
pending_meta->update_generation(meta_); // clone index metadata generation
|
||||
|
||||
modified |= !to_sync.empty(); // new files added
|
||||
// new files were added or no payload was supplied and it's different compared to the previous one
|
||||
auto& committed_payload = committed_state_->first->payload();
|
||||
|
||||
modified |= (!to_sync.empty()
|
||||
|| (payload.null() && !committed_payload.null())
|
||||
|| (!payload.null() && (committed_payload.null() || payload != committed_payload)));
|
||||
|
||||
// only flush a new index version upon a new index or a metadata change
|
||||
if (!modified) {
|
||||
return pending_context_t();
|
||||
}
|
||||
|
||||
pending_meta->payload(payload);
|
||||
pending_meta->seg_counter_.store(meta_.counter()); // ensure counter() >= max(seg#)
|
||||
|
||||
pending_context_t pending_context;
|
||||
|
@ -2257,7 +2263,7 @@ index_writer::pending_context_t index_writer::flush_all() {
|
|||
return pending_context;
|
||||
}
|
||||
|
||||
bool index_writer::start() {
|
||||
bool index_writer::start(const bytes_ref& payload) {
|
||||
assert(!commit_lock_.try_lock()); // already locked
|
||||
|
||||
REGISTER_TIMER_DETAILED();
|
||||
|
@ -2268,7 +2274,7 @@ bool index_writer::start() {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto to_commit = flush_all();
|
||||
auto to_commit = flush_all(payload);
|
||||
|
||||
if (!to_commit) {
|
||||
// nothing to commit, no transaction started
|
||||
|
|
|
@ -590,12 +590,13 @@ class IRESEARCH_API index_writer:
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief begins the two-phase transaction
|
||||
/// @param payload arbitrary user supplied data to store in the index
|
||||
/// @returns true if transaction has been sucessflully started
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
bool begin() {
|
||||
bool begin(const bytes_ref& payload = bytes_ref::NIL) {
|
||||
SCOPED_LOCK(commit_lock_);
|
||||
|
||||
return start();
|
||||
return start(payload);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -609,14 +610,15 @@ class IRESEARCH_API index_writer:
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief make all buffered changes visible for readers
|
||||
/// @param payload arbitrary user supplied data to store in the index
|
||||
///
|
||||
/// Note that if begin() has been already called commit() is
|
||||
/// @note that if begin() has been already called commit() is
|
||||
/// relatively lightweight operation
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void commit() {
|
||||
void commit(const bytes_ref& payload = bytes_ref::NIL) {
|
||||
SCOPED_LOCK(commit_lock_);
|
||||
|
||||
start();
|
||||
start(payload);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -1005,12 +1007,12 @@ class IRESEARCH_API index_writer:
|
|||
committed_state_t&& committed_state
|
||||
) NOEXCEPT;
|
||||
|
||||
pending_context_t flush_all();
|
||||
pending_context_t flush_all(const bytes_ref& payload);
|
||||
|
||||
flush_context_ptr get_flush_context(bool shared = true);
|
||||
active_segment_context get_segment_context(flush_context& ctx); // return a usable segment or a nullptr segment if retry is required (e.g. no free segments available)
|
||||
|
||||
bool start(); // starts transaction
|
||||
bool start(const bytes_ref& payload); // starts transaction
|
||||
void finish(); // finishes transaction
|
||||
void abort(); // aborts transaction
|
||||
|
||||
|
|
|
@ -254,6 +254,15 @@ struct term_collector final: public irs::sort::term_collector {
|
|||
}
|
||||
};
|
||||
|
||||
FORCE_INLINE float_t tf(float_t freq) NOEXCEPT {
|
||||
static_assert(
|
||||
std::is_same<decltype(std::sqrt(freq)), float_t>::value,
|
||||
"float_t expected"
|
||||
);
|
||||
|
||||
return std::sqrt(freq);
|
||||
}
|
||||
|
||||
NS_END // LOCAL
|
||||
|
||||
NS_ROOT
|
||||
|
@ -287,27 +296,18 @@ struct stats final {
|
|||
|
||||
typedef bm25_sort::score_t score_t;
|
||||
|
||||
class const_scorer final : public irs::sort::scorer_base<bm25::score_t> {
|
||||
struct const_score_ctx final : public irs::sort::score_ctx {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(scorer)
|
||||
|
||||
explicit const_scorer(irs::boost_t boost) NOEXCEPT
|
||||
explicit const_score_ctx(irs::boost_t boost) NOEXCEPT
|
||||
: boost_(boost) {
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
score_cast(score_buf) = boost_;
|
||||
}
|
||||
|
||||
private:
|
||||
const irs::boost_t boost_;
|
||||
}; // const_scorer
|
||||
}; // const_score_ctx
|
||||
|
||||
class scorer : public irs::sort::scorer_base<bm25::score_t> {
|
||||
struct score_ctx : public irs::sort::score_ctx {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(scorer)
|
||||
|
||||
scorer(
|
||||
score_ctx(
|
||||
float_t k,
|
||||
irs::boost_t boost,
|
||||
const bm25::stats& stats,
|
||||
|
@ -318,32 +318,20 @@ class scorer : public irs::sort::scorer_base<bm25::score_t> {
|
|||
assert(freq_);
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
const float_t freq = tf();
|
||||
score_cast(score_buf) = num_ * freq / (norm_const_ + freq);
|
||||
}
|
||||
|
||||
protected:
|
||||
FORCE_INLINE float_t tf() const NOEXCEPT {
|
||||
return float_t(std::sqrt(freq_->value));
|
||||
}
|
||||
|
||||
const frequency* freq_; // document frequency
|
||||
float_t num_; // partially precomputed numerator : boost * (k + 1) * idf
|
||||
float_t norm_const_; // 'k' factor
|
||||
}; // scorer
|
||||
}; // score_ctx
|
||||
|
||||
class norm_scorer final : public scorer {
|
||||
struct norm_score_ctx final : public score_ctx {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(norm_scorer)
|
||||
|
||||
norm_scorer(
|
||||
norm_score_ctx(
|
||||
float_t k,
|
||||
irs::boost_t boost,
|
||||
const bm25::stats& stats,
|
||||
const frequency* freq,
|
||||
irs::norm&& norm) NOEXCEPT
|
||||
: scorer(k, boost, stats, freq),
|
||||
: score_ctx(k, boost, stats, freq),
|
||||
norm_(std::move(norm)) {
|
||||
// if there is no norms, assume that b==0
|
||||
if (!norm_.empty()) {
|
||||
|
@ -352,15 +340,9 @@ class norm_scorer final : public scorer {
|
|||
}
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
const float_t freq = tf();
|
||||
score_cast(score_buf) = num_ * freq / (norm_const_ + norm_length_ * norm_.read() + freq);
|
||||
}
|
||||
|
||||
private:
|
||||
irs::norm norm_;
|
||||
float_t norm_length_{ 0.f }; // precomputed 'k*b/avgD' if norms present, '0' otherwise
|
||||
}; // norm_scorer
|
||||
}; // norm_score_ctx
|
||||
|
||||
class sort final : public irs::sort::prepared_basic<bm25::score_t, bm25::stats> {
|
||||
public:
|
||||
|
@ -428,7 +410,7 @@ class sort final : public irs::sort::prepared_basic<bm25::score_t, bm25::stats>
|
|||
return irs::memory::make_unique<field_collector>();
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, score_f> prepare_scorer(
|
||||
const sub_reader& segment,
|
||||
const term_reader& field,
|
||||
const byte_type* query_stats,
|
||||
|
@ -438,7 +420,7 @@ class sort final : public irs::sort::prepared_basic<bm25::score_t, bm25::stats>
|
|||
auto& freq = doc_attrs.get<frequency>();
|
||||
|
||||
if (!freq) {
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
auto& stats = stats_cast(query_stats);
|
||||
|
@ -450,18 +432,32 @@ class sort final : public irs::sort::prepared_basic<bm25::score_t, bm25::stats>
|
|||
|
||||
if (!doc) {
|
||||
// we need 'document' attribute to be exposed
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
if (norm.reset(segment, field.meta().norm, *doc)) {
|
||||
return bm25::scorer::make<bm25::norm_scorer>(
|
||||
k_, boost, stats, freq.get(), std::move(norm)
|
||||
);
|
||||
return {
|
||||
memory::make_unique<bm25::norm_score_ctx>(k_, boost, stats, freq.get(), std::move(norm)),
|
||||
[](const void* ctx, byte_type* score_buf) NOEXCEPT {
|
||||
auto& state = *static_cast<const bm25::norm_score_ctx*>(ctx);
|
||||
|
||||
const float_t tf = ::tf(state.freq_->value);
|
||||
irs::sort::score_cast<score_t>(score_buf) = state.num_ * tf / (state.norm_const_ + state.norm_length_ * state.norm_.read() + tf);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// BM11
|
||||
return bm25::scorer::make<bm25::scorer>(k_, boost, stats, freq.get());
|
||||
return {
|
||||
memory::make_unique<bm25::score_ctx>(k_, boost, stats, freq.get()),
|
||||
[](const void* ctx, byte_type* score_buf) NOEXCEPT {
|
||||
auto& state = *static_cast<const bm25::score_ctx*>(ctx);
|
||||
|
||||
const float_t tf = ::tf(state.freq_->value);
|
||||
irs::sort::score_cast<score_t>(score_buf) = state.num_ * tf / (state.norm_const_ + tf);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual irs::sort::term_collector::ptr prepare_term_collector() const override {
|
||||
|
|
|
@ -130,14 +130,15 @@ class conjunction : public doc_iterator_base {
|
|||
}
|
||||
|
||||
if (scores_.empty()) {
|
||||
prepare_score(ord, [](byte_type*) { /*NOOP*/});
|
||||
prepare_score(ord, nullptr, [](const void*, byte_type*) { /*NOOP*/});
|
||||
} else {
|
||||
// prepare score
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
order_->prepare_score(score);
|
||||
for (auto* it_score : scores_) {
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = *static_cast<const conjunction*>(ctx);
|
||||
self.order_->prepare_score(score);
|
||||
for (auto* it_score : self.scores_) {
|
||||
it_score->evaluate();
|
||||
order_->add(score, it_score->c_str());
|
||||
self.order_->add(score, it_score->c_str());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -155,29 +155,32 @@ class basic_disjunction final : public doc_iterator_base {
|
|||
if (lhs_.score != &irs::score::no_score()
|
||||
&& rhs_.score != &irs::score::no_score()) {
|
||||
// both sub-iterators has score
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
score_iterator_impl(lhs_, score);
|
||||
score_iterator_impl(rhs_, score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = *static_cast<const basic_disjunction*>(ctx);
|
||||
self.ord_->prepare_score(score);
|
||||
self.score_iterator_impl(self.lhs_, score);
|
||||
self.score_iterator_impl(self.rhs_, score);
|
||||
});
|
||||
} else if (lhs_.score != &irs::score::no_score()) {
|
||||
// only left sub-iterator has score
|
||||
assert(rhs_.score == &irs::score::no_score());
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
score_iterator_impl(lhs_, score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = *static_cast<const basic_disjunction*>(ctx);
|
||||
self.ord_->prepare_score(score);
|
||||
self.score_iterator_impl(self.lhs_, score);
|
||||
});
|
||||
} else if (rhs_.score != &irs::score::no_score()) {
|
||||
// only right sub-iterator has score
|
||||
assert(lhs_.score == &irs::score::no_score());
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
score_iterator_impl(rhs_, score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = *static_cast<const basic_disjunction*>(ctx);
|
||||
self.ord_->prepare_score(score);
|
||||
self.score_iterator_impl(self.rhs_, score);
|
||||
});
|
||||
} else {
|
||||
assert(lhs_.score == &irs::score::no_score());
|
||||
assert(rhs_.score == &irs::score::no_score());
|
||||
prepare_score(ord, [](byte_type*) {/*NOOP*/});
|
||||
prepare_score(ord, nullptr, [](const void*, byte_type*) {/*NOOP*/});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +199,7 @@ class basic_disjunction final : public doc_iterator_base {
|
|||
}
|
||||
}
|
||||
|
||||
void score_iterator_impl(doc_iterator_t& it, byte_type* lhs) {
|
||||
void score_iterator_impl(doc_iterator_t& it, byte_type* lhs) const {
|
||||
auto doc = it.value();
|
||||
|
||||
if (doc < doc_.value) {
|
||||
|
@ -210,8 +213,8 @@ class basic_disjunction final : public doc_iterator_base {
|
|||
}
|
||||
}
|
||||
|
||||
doc_iterator_t lhs_;
|
||||
doc_iterator_t rhs_;
|
||||
mutable doc_iterator_t lhs_;
|
||||
mutable doc_iterator_t rhs_;
|
||||
document doc_;
|
||||
const order::prepared* ord_;
|
||||
}; // basic_disjunction
|
||||
|
@ -353,21 +356,22 @@ class small_disjunction : public doc_iterator_base {
|
|||
|
||||
// prepare score
|
||||
if (scored_itrs_.empty()) {
|
||||
prepare_score(ord, [](byte_type*){ /*NOOP*/ });
|
||||
prepare_score(ord, nullptr, [](const void*, byte_type*){ /*NOOP*/ });
|
||||
} else {
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = *static_cast<const small_disjunction*>(ctx);
|
||||
self.ord_->prepare_score(score);
|
||||
|
||||
for (auto& it : scored_itrs_) {
|
||||
for (auto& it : self.scored_itrs_) {
|
||||
auto doc = it.value();
|
||||
|
||||
if (doc < doc_.value) {
|
||||
doc = it->seek(doc_.value);
|
||||
if (doc < self.doc_.value) {
|
||||
doc = it->seek(self.doc_.value);
|
||||
}
|
||||
|
||||
if (doc == doc_.value) {
|
||||
if (doc == self.doc_.value) {
|
||||
it.score->evaluate();
|
||||
ord_->add(score, it.score->c_str());
|
||||
self.ord_->add(score, it.score->c_str());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -497,9 +501,10 @@ class disjunction : public doc_iterator_base {
|
|||
std::iota(heap_.begin(), heap_.end(), size_t(0));
|
||||
|
||||
// prepare score
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
score_impl(score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = const_cast<disjunction&>(*static_cast<const disjunction*>(ctx));
|
||||
self.ord_->prepare_score(score);
|
||||
self.score_impl(score);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -105,9 +105,12 @@ class min_match_disjunction : public doc_iterator_base {
|
|||
std::iota(heap_.begin(), heap_.end(), size_t(0));
|
||||
|
||||
// prepare score
|
||||
prepare_score(ord, [this](byte_type* score) {
|
||||
ord_->prepare_score(score);
|
||||
score_impl(score);
|
||||
prepare_score(ord, this, [](const void* ctx, byte_type* score) {
|
||||
auto& self = const_cast<min_match_disjunction&>(
|
||||
*static_cast<const min_match_disjunction*>(ctx)
|
||||
);
|
||||
self.ord_->prepare_score(score);
|
||||
self.score_impl(score);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ DEFINE_ATTRIBUTE_TYPE(iresearch::score)
|
|||
}
|
||||
|
||||
score::score() NOEXCEPT
|
||||
: func_([](byte_type*){}) {
|
||||
: func_([](const void*, byte_type*){}) {
|
||||
}
|
||||
|
||||
NS_END // ROOT
|
||||
|
|
|
@ -35,7 +35,7 @@ NS_ROOT
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
class IRESEARCH_API score : public attribute {
|
||||
public:
|
||||
typedef std::function<void(byte_type*)> score_f;
|
||||
typedef void(*score_f)(const void*, byte_type*);
|
||||
|
||||
DECLARE_ATTRIBUTE_TYPE();
|
||||
|
||||
|
@ -62,10 +62,14 @@ class IRESEARCH_API score : public attribute {
|
|||
|
||||
void evaluate() const {
|
||||
assert(func_);
|
||||
func_(leak());
|
||||
(*func_)(ctx_, leak());
|
||||
}
|
||||
|
||||
bool prepare(const order::prepared& ord, score_f&& func) {
|
||||
bool prepare(const order::prepared& ord,
|
||||
const void* ctx,
|
||||
const score_f func) {
|
||||
assert(func);
|
||||
|
||||
if (ord.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -73,7 +77,8 @@ class IRESEARCH_API score : public attribute {
|
|||
value_.resize(ord.score_size());
|
||||
ord.prepare_score(leak());
|
||||
|
||||
func_ = std::move(func);
|
||||
ctx_ = ctx;
|
||||
func_ = func;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -83,8 +88,9 @@ class IRESEARCH_API score : public attribute {
|
|||
}
|
||||
|
||||
IRESEARCH_API_PRIVATE_VARIABLES_BEGIN
|
||||
bstring value_;
|
||||
score_f func_;
|
||||
bstring value_; // score buffer
|
||||
const void* ctx_{}; // arbitrary scoring context
|
||||
score_f func_{}; // scoring function
|
||||
IRESEARCH_API_PRIVATE_VARIABLES_END
|
||||
}; // score
|
||||
|
||||
|
|
|
@ -29,57 +29,50 @@ NS_ROOT
|
|||
void basic_doc_iterator_base::prepare_score(
|
||||
const order::prepared& order,
|
||||
order::prepared::scorers&& scorers) {
|
||||
struct scorer_ref {
|
||||
explicit scorer_ref(const std::pair<sort::scorer::ptr, size_t>& bucket) NOEXCEPT
|
||||
: scorer(bucket.first.get()), offset(bucket.second) {
|
||||
assert(scorer);
|
||||
}
|
||||
|
||||
irs::sort::scorer* scorer;
|
||||
size_t offset;
|
||||
}; // scorer_ref
|
||||
|
||||
scorers_ = std::move(scorers);
|
||||
|
||||
switch (scorers_.size()) {
|
||||
case 0: {
|
||||
// let order initialize empty score
|
||||
doc_iterator_base::prepare_score(order, [](byte_type*){ });
|
||||
doc_iterator_base::prepare_score(order, nullptr, [](const void*, byte_type*){ });
|
||||
} break;
|
||||
case 1: {
|
||||
const scorer_ref ref(scorers_[0]);
|
||||
auto& scorer = scorers_[0];
|
||||
|
||||
if (ref.offset) {
|
||||
doc_iterator_base::prepare_score(order, [ref](byte_type* score) {
|
||||
ref.scorer->score(score + ref.offset);
|
||||
if (scorer.offset) {
|
||||
doc_iterator_base::prepare_score(
|
||||
order, &scorer,
|
||||
[](const void* ctx, byte_type* score) {
|
||||
auto& scorer = *static_cast<const order::prepared::scorers::entry*>(ctx);
|
||||
(*scorer.func)(scorer.ctx.get(), score + scorer.offset);
|
||||
});
|
||||
} else {
|
||||
auto* scorer = ref.scorer;
|
||||
|
||||
doc_iterator_base::prepare_score(order, [scorer](byte_type* score) {
|
||||
scorer->score(score);
|
||||
});
|
||||
doc_iterator_base::prepare_score(order, scorer.ctx.get(), scorer.func);
|
||||
}
|
||||
} break;
|
||||
case 2: {
|
||||
const scorer_ref first(scorers_[0]);
|
||||
const scorer_ref second(scorers_[1]);
|
||||
|
||||
if (first.offset) {
|
||||
doc_iterator_base::prepare_score(order, [first, second](byte_type* score) {
|
||||
first.scorer->score(score + first.offset);
|
||||
second.scorer->score(score + second.offset);
|
||||
if (scorers_[0].offset) {
|
||||
doc_iterator_base::prepare_score(
|
||||
order, &scorers_, [](const void* ctx, byte_type* score) {
|
||||
auto& scorers = *static_cast<const order::prepared::scorers*>(ctx);
|
||||
(*scorers[0].func)(scorers[0].ctx.get(), score + scorers[0].offset);
|
||||
(*scorers[1].func)(scorers[1].ctx.get(), score + scorers[1].offset);
|
||||
});
|
||||
} else {
|
||||
doc_iterator_base::prepare_score(order, [first, second](byte_type* score) {
|
||||
first.scorer->score(score);
|
||||
second.scorer->score(score + second.offset);
|
||||
doc_iterator_base::prepare_score(
|
||||
order, &scorers_, [](const void* ctx, byte_type* score) {
|
||||
auto& scorers = *static_cast<const order::prepared::scorers*>(ctx);
|
||||
(*scorers[0].func)(scorers[0].ctx.get(), score);
|
||||
(*scorers[1].func)(scorers[1].ctx.get(), score + scorers[1].offset);
|
||||
});
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
doc_iterator_base::prepare_score(order, [this](byte_type* score) {
|
||||
scorers_.score(score);
|
||||
doc_iterator_base::prepare_score(
|
||||
order, &scorers_,
|
||||
[](const void* ctx, byte_type* score) {
|
||||
auto& scorers = *static_cast<const order::prepared::scorers*>(ctx);
|
||||
scorers.score(score);
|
||||
});
|
||||
} break;
|
||||
}
|
||||
|
@ -113,8 +106,9 @@ basic_doc_iterator::basic_doc_iterator(
|
|||
assert(doc_);
|
||||
|
||||
// set scorers
|
||||
prepare_score(ord, ord.prepare_scorers(
|
||||
segment, field, stats_, it_->attributes(), boost
|
||||
prepare_score(
|
||||
ord,
|
||||
ord.prepare_scorers(segment, field, stats_, it_->attributes(), boost
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,9 @@ class IRESEARCH_API doc_iterator_base : public doc_iterator {
|
|||
|
||||
void prepare_score(
|
||||
const order::prepared& order,
|
||||
score::score_f&& func) {
|
||||
if (scr_.prepare(order, std::move(func))) {
|
||||
const void* ctx,
|
||||
score::score_f func) {
|
||||
if (scr_.prepare(order, ctx, func)) {
|
||||
attrs_.emplace(scr_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,10 +37,6 @@ sort::sort(const type_id& type) NOEXCEPT
|
|||
: type_(&type) {
|
||||
}
|
||||
|
||||
sort::prepared::prepared(attribute_view&& attrs) NOEXCEPT
|
||||
: attrs_(std::move(attrs)) {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// --SECTION-- order
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -298,9 +294,9 @@ order::prepared::scorers::scorers(
|
|||
segment, field, stats_buf + entry.stats_offset, doc, boost
|
||||
);
|
||||
|
||||
if (scorer) {
|
||||
if (scorer.second) {
|
||||
// skip empty scorers
|
||||
scorers_.emplace_back(std::move(scorer), entry.score_offset);
|
||||
scorers_.emplace_back(std::move(scorer.first), scorer.second, entry.score_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,8 +317,8 @@ order::prepared::scorers& order::prepared::scorers::operator=(
|
|||
|
||||
void order::prepared::scorers::score(byte_type* scr) const {
|
||||
for (auto& scorer : scorers_) {
|
||||
assert(scorer.first);
|
||||
scorer.first->score(scr + scorer.second);
|
||||
assert(scorer.func);
|
||||
(*scorer.func)(scorer.ctx.get(), scr + scorer.offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ struct index_reader;
|
|||
struct sub_reader;
|
||||
struct term_reader;
|
||||
|
||||
typedef bool (*score_less_f)(const byte_type* lhs, const byte_type* rhs);
|
||||
typedef bool(*score_less_f)(const byte_type* lhs, const byte_type* rhs);
|
||||
typedef void(*score_f)(const void* ctx, byte_type*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @class sort
|
||||
|
@ -98,29 +99,23 @@ class IRESEARCH_API sort {
|
|||
/// @brief stateful object used for computing the document score based on the
|
||||
/// stored state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class IRESEARCH_API scorer {
|
||||
class IRESEARCH_API score_ctx {
|
||||
public:
|
||||
DECLARE_UNIQUE_PTR(scorer);
|
||||
DEFINE_FACTORY_INLINE(scorer)
|
||||
DECLARE_UNIQUE_PTR(score_ctx);
|
||||
|
||||
virtual ~scorer() = default;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set the document score based on the stored state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
virtual void score(byte_type* score_buf) = 0;
|
||||
virtual ~score_ctx() = default;
|
||||
}; // scorer
|
||||
|
||||
template <typename T>
|
||||
class scorer_base : public scorer {
|
||||
public:
|
||||
typedef T score_t;
|
||||
template<typename T>
|
||||
FORCE_INLINE static T& score_cast(byte_type* score_buf) NOEXCEPT {
|
||||
assert(score_buf);
|
||||
return *reinterpret_cast<T*>(score_buf);
|
||||
}
|
||||
|
||||
FORCE_INLINE static T& score_cast(byte_type* score_buf) NOEXCEPT {
|
||||
assert(score_buf);
|
||||
return *reinterpret_cast<T*>(score_buf);
|
||||
}
|
||||
}; // scorer_base
|
||||
template<typename T>
|
||||
FORCE_INLINE static const T& score_cast(const byte_type* score_buf) NOEXCEPT {
|
||||
return score_cast<T>(const_cast<byte_type*>(score_buf));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief object used for collecting index statistics, for a specific matched
|
||||
|
@ -164,19 +159,13 @@ class IRESEARCH_API sort {
|
|||
/// @class sort::prepared
|
||||
/// @brief base class for all prepared(compiled) sort entries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class IRESEARCH_API prepared : public util::attribute_view_provider {
|
||||
class IRESEARCH_API prepared {
|
||||
public:
|
||||
DECLARE_UNIQUE_PTR(prepared);
|
||||
|
||||
prepared() = default;
|
||||
explicit prepared(attribute_view&& attrs) NOEXCEPT;
|
||||
virtual ~prepared() = default;
|
||||
|
||||
using util::attribute_view_provider::attributes;
|
||||
virtual attribute_view& attributes() NOEXCEPT override final {
|
||||
return attrs_;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief store collected index statistics into 'stats' of the
|
||||
/// current 'filter'
|
||||
|
@ -217,13 +206,12 @@ class IRESEARCH_API sort {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a stateful scorer used for computation of document scores
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, score_f> prepare_scorer(
|
||||
const sub_reader& segment,
|
||||
const term_reader& field,
|
||||
const byte_type* stats,
|
||||
const attribute_view& doc_attrs,
|
||||
boost_t boost
|
||||
) const = 0;
|
||||
boost_t boost) const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create an object to be used for collecting index statistics, one
|
||||
|
@ -630,10 +618,7 @@ class IRESEARCH_API order final {
|
|||
/// @note always called on each matched 'field' irrespective of if it
|
||||
/// contains a matching 'term'
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void collect(
|
||||
const sub_reader& segment,
|
||||
const term_reader& field
|
||||
) const;
|
||||
void collect(const sub_reader& segment, const term_reader& field) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collect term related statistics, i.e. term used in the filter
|
||||
|
@ -684,6 +669,18 @@ class IRESEARCH_API order final {
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
class IRESEARCH_API scorers: private util::noncopyable { // noncopyable required by MSVC
|
||||
public:
|
||||
struct entry {
|
||||
entry(sort::score_ctx::ptr&& ctx, score_f func, size_t offset)
|
||||
: ctx(std::move(ctx)),
|
||||
func(func),
|
||||
offset(offset) {
|
||||
}
|
||||
|
||||
sort::score_ctx::ptr ctx;
|
||||
score_f func;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
scorers() = default;
|
||||
scorers(
|
||||
const prepared_order_t& buckets,
|
||||
|
@ -699,7 +696,7 @@ class IRESEARCH_API order final {
|
|||
|
||||
void score(byte_type* score) const;
|
||||
|
||||
const std::pair<sort::scorer::ptr, size_t>& operator[](size_t i) const NOEXCEPT {
|
||||
const entry& operator[](size_t i) const NOEXCEPT {
|
||||
assert(i < scorers_.size());
|
||||
return scorers_[i];
|
||||
}
|
||||
|
@ -710,7 +707,7 @@ class IRESEARCH_API order final {
|
|||
|
||||
private:
|
||||
IRESEARCH_API_PRIVATE_VARIABLES_BEGIN
|
||||
std::vector<std::pair<sort::scorer::ptr, size_t>> scorers_; // scorer + offset
|
||||
std::vector<entry> scorers_; // scorer + offset
|
||||
IRESEARCH_API_PRIVATE_VARIABLES_END
|
||||
}; // scorers
|
||||
|
||||
|
|
|
@ -226,6 +226,15 @@ struct term_collector final: public irs::sort::term_collector {
|
|||
}
|
||||
};
|
||||
|
||||
FORCE_INLINE float_t tfidf(float_t freq, float_t idf) NOEXCEPT {
|
||||
static_assert(
|
||||
std::is_same<decltype(std::sqrt(freq)), float_t>::value,
|
||||
"float_t expected"
|
||||
);
|
||||
|
||||
return idf * std::sqrt(freq);
|
||||
}
|
||||
|
||||
NS_END // LOCAL
|
||||
|
||||
NS_ROOT
|
||||
|
@ -240,27 +249,16 @@ struct idf final : attribute {
|
|||
|
||||
typedef tfidf_sort::score_t score_t;
|
||||
|
||||
class const_scorer final : public irs::sort::scorer_base<tfidf::score_t> {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(const_scorer)
|
||||
|
||||
explicit const_scorer(irs::boost_t boost) NOEXCEPT
|
||||
struct const_score_ctx final : public irs::sort::score_ctx {
|
||||
explicit const_score_ctx(irs::boost_t boost) NOEXCEPT
|
||||
: boost_(boost) {
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
score_cast(score_buf) = boost_;
|
||||
}
|
||||
|
||||
private:
|
||||
const irs::boost_t boost_;
|
||||
}; // const_scorer
|
||||
}; // const_score_ctx
|
||||
|
||||
class scorer : public irs::sort::scorer_base<tfidf::score_t> {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(scorer)
|
||||
|
||||
scorer(
|
||||
struct score_ctx : public irs::sort::score_ctx {
|
||||
score_ctx(
|
||||
irs::boost_t boost,
|
||||
const tfidf::idf& idf,
|
||||
const frequency* freq) NOEXCEPT
|
||||
|
@ -269,40 +267,22 @@ class scorer : public irs::sort::scorer_base<tfidf::score_t> {
|
|||
assert(freq_);
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
score_cast(score_buf) = tfidf();
|
||||
}
|
||||
|
||||
protected:
|
||||
FORCE_INLINE float_t tfidf() const NOEXCEPT {
|
||||
return idf_ * float_t(std::sqrt(freq_->value));
|
||||
}
|
||||
|
||||
private:
|
||||
float_t idf_; // precomputed : boost * idf
|
||||
const frequency* freq_;
|
||||
}; // scorer
|
||||
}; // score_ctx
|
||||
|
||||
class norm_scorer final : public scorer {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(norm_scorer)
|
||||
|
||||
norm_scorer(
|
||||
struct norm_score_ctx final : public score_ctx {
|
||||
norm_score_ctx(
|
||||
irs::norm&& norm,
|
||||
irs::boost_t boost,
|
||||
const tfidf::idf& idf,
|
||||
const frequency* freq) NOEXCEPT
|
||||
: scorer(boost, idf, freq),
|
||||
: score_ctx(boost, idf, freq),
|
||||
norm_(std::move(norm)) {
|
||||
}
|
||||
|
||||
virtual void score(byte_type* score_buf) NOEXCEPT override {
|
||||
score_cast(score_buf) = tfidf() * norm_.read();
|
||||
}
|
||||
|
||||
private:
|
||||
irs::norm norm_;
|
||||
}; // norm_scorer
|
||||
}; // norm_score_ctx
|
||||
|
||||
class sort final: irs::sort::prepared_basic<tfidf::score_t, tfidf::idf> {
|
||||
public:
|
||||
|
@ -352,7 +332,7 @@ class sort final: irs::sort::prepared_basic<tfidf::score_t, tfidf::idf> {
|
|||
return irs::memory::make_unique<field_collector>();
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, score_f> prepare_scorer(
|
||||
const sub_reader& segment,
|
||||
const term_reader& field,
|
||||
const byte_type* stats_buf,
|
||||
|
@ -362,7 +342,7 @@ class sort final: irs::sort::prepared_basic<tfidf::score_t, tfidf::idf> {
|
|||
auto& freq = doc_attrs.get<frequency>();
|
||||
|
||||
if (!freq) {
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
auto& stats = stats_cast(stats_buf);
|
||||
|
@ -375,18 +355,28 @@ class sort final: irs::sort::prepared_basic<tfidf::score_t, tfidf::idf> {
|
|||
|
||||
if (!doc) {
|
||||
// we need 'document' attribute to be exposed
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
if (norm.reset(segment, field.meta().norm, *doc)) {
|
||||
return tfidf::scorer::make<tfidf::norm_scorer>(
|
||||
std::move(norm), boost, stats, freq.get()
|
||||
);
|
||||
return {
|
||||
memory::make_unique<tfidf::norm_score_ctx>(std::move(norm), boost, stats, freq.get()),
|
||||
[](const void* ctx, byte_type* score_buf) NOEXCEPT {
|
||||
auto& state = *static_cast<const tfidf::norm_score_ctx*>(ctx);
|
||||
irs::sort::score_cast<tfidf::score_t>(score_buf) = ::tfidf(state.freq_->value, state.idf_)*state.norm_.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return tfidf::scorer::make<tfidf::scorer>(boost, stats, freq.get());
|
||||
return {
|
||||
memory::make_unique<tfidf::score_ctx>(boost, stats, freq.get()),
|
||||
[](const void* ctx, byte_type* score_buf) NOEXCEPT {
|
||||
auto& state = *static_cast<const tfidf::score_ctx*>(ctx);
|
||||
irs::sort::score_cast<score_t>(score_buf) = ::tfidf(state.freq_->value, state.idf_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual irs::sort::term_collector::ptr prepare_term_collector() const override {
|
||||
|
|
|
@ -7,7 +7,7 @@ export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$(pwd)/bin"
|
|||
ulimit -c unlimited
|
||||
|
||||
for i in `seq 1 1`; do
|
||||
for j in 1 5 10 15 20 25; do
|
||||
for j in 1 ; do
|
||||
MAX_LINES=${j}000000
|
||||
|
||||
rm -r iresearch.data || {
|
||||
|
|
|
@ -7,7 +7,7 @@ export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$(pwd)/build/bin"
|
|||
ulimit -c unlimited
|
||||
|
||||
for i in `seq 1 1`; do
|
||||
for j in 1 5 10 15 20 25; do
|
||||
for j in 25 ; do
|
||||
MAX_LINES=${j}000000
|
||||
|
||||
# search
|
||||
|
|
|
@ -32,14 +32,13 @@
|
|||
|
||||
using namespace iresearch;
|
||||
|
||||
NS_BEGIN(tests)
|
||||
NS_BEGIN(detail)
|
||||
TEST(index_meta_tests, memory_directory_read_write_10) {
|
||||
auto codec = irs::formats::get("1_0");
|
||||
ASSERT_NE(nullptr, codec);
|
||||
irs::memory_directory dir;
|
||||
auto writer = codec->get_index_meta_writer();
|
||||
|
||||
void index_meta_read_write(iresearch::directory& dir, const iresearch::format& codec) {
|
||||
auto writer = codec.get_index_meta_writer();
|
||||
|
||||
/* check that there are no files in
|
||||
* a directory */
|
||||
// check that there are no files in a directory
|
||||
std::vector<std::string> files;
|
||||
auto list_files = [&files] (std::string& name) {
|
||||
files.emplace_back(std::move(name));
|
||||
|
@ -48,34 +47,34 @@ void index_meta_read_write(iresearch::directory& dir, const iresearch::format& c
|
|||
ASSERT_TRUE(dir.visit(list_files));
|
||||
ASSERT_TRUE(files.empty());
|
||||
|
||||
/* create index metadata and
|
||||
* write it into the specified
|
||||
* directory */
|
||||
iresearch::index_meta meta_orig;
|
||||
// create index metadata and write it into the specified directory
|
||||
irs::index_meta meta_orig;
|
||||
ASSERT_TRUE(meta_orig.payload().null());
|
||||
|
||||
// set payload
|
||||
const irs::bytes_ref payload = ref_cast<byte_type>(string_ref("payload"));
|
||||
const_cast<bytes_ref&>(meta_orig.payload()) = payload;
|
||||
|
||||
ASSERT_TRUE(writer->prepare(dir, meta_orig));
|
||||
|
||||
/* we should increase meta generation
|
||||
* after we write to directory */
|
||||
// we should increase meta generation after we write to directory
|
||||
EXPECT_EQ(1, meta_orig.generation());
|
||||
|
||||
/* check that files was successfully
|
||||
* written to directory */
|
||||
// check that files were successfully
|
||||
// written to directory
|
||||
files.clear();
|
||||
ASSERT_TRUE(dir.visit(list_files));
|
||||
EXPECT_EQ(1, files.size());
|
||||
EXPECT_EQ(files[0], iresearch::string_ref("pending_segments_1"));
|
||||
EXPECT_EQ(files[0], irs::string_ref("pending_segments_1"));
|
||||
|
||||
writer->commit();
|
||||
|
||||
/* create index metadata and
|
||||
* read it from specified the
|
||||
* directory */
|
||||
iresearch::index_meta meta_read;
|
||||
// create index metadata and read it from the specified directory
|
||||
irs::index_meta meta_read;
|
||||
{
|
||||
std::string segments_file;
|
||||
|
||||
auto reader = codec.get_index_meta_reader();
|
||||
auto reader = codec->get_index_meta_reader();
|
||||
const bool index_exists = reader->last_segments_file(dir, segments_file);
|
||||
|
||||
ASSERT_TRUE(index_exists);
|
||||
|
@ -85,22 +84,74 @@ void index_meta_read_write(iresearch::directory& dir, const iresearch::format& c
|
|||
EXPECT_EQ(meta_orig.counter(), meta_read.counter());
|
||||
EXPECT_EQ(meta_orig.generation(), meta_read.generation());
|
||||
EXPECT_EQ(meta_orig.size(), meta_read.size());
|
||||
EXPECT_TRUE(meta_read.payload().null());
|
||||
|
||||
EXPECT_NE(meta_orig, meta_read);
|
||||
const_cast<bytes_ref&>(meta_orig.payload()) = bytes_ref::NIL;
|
||||
EXPECT_EQ(meta_orig, meta_read);
|
||||
}
|
||||
|
||||
NS_END // detail
|
||||
NS_END // tests
|
||||
|
||||
TEST(index_meta_tests, memory_directory_read_write) {
|
||||
auto codec = irs::formats::get("1_0");
|
||||
TEST(index_meta_tests, memory_directory_read_write_11) {
|
||||
auto codec = irs::formats::get("1_1");
|
||||
ASSERT_NE(nullptr, codec);
|
||||
irs::memory_directory dir;
|
||||
tests::detail::index_meta_read_write(dir, *codec);
|
||||
auto writer = codec->get_index_meta_writer();
|
||||
|
||||
// check that there are no files in a directory
|
||||
std::vector<std::string> files;
|
||||
auto list_files = [&files] (std::string& name) {
|
||||
files.emplace_back(std::move(name));
|
||||
return true;
|
||||
};
|
||||
ASSERT_TRUE(dir.visit(list_files));
|
||||
ASSERT_TRUE(files.empty());
|
||||
|
||||
// create index metadata and write it into the specified directory
|
||||
irs::index_meta meta_orig;
|
||||
ASSERT_TRUE(meta_orig.payload().null());
|
||||
|
||||
// set payload
|
||||
const irs::bytes_ref payload = ref_cast<byte_type>(string_ref("payload"));
|
||||
const_cast<bytes_ref&>(meta_orig.payload()) = payload;
|
||||
|
||||
ASSERT_TRUE(writer->prepare(dir, meta_orig));
|
||||
|
||||
// we should increase meta generation after we write to directory
|
||||
EXPECT_EQ(1, meta_orig.generation());
|
||||
|
||||
// check that files were successfully
|
||||
// written to directory
|
||||
files.clear();
|
||||
ASSERT_TRUE(dir.visit(list_files));
|
||||
EXPECT_EQ(1, files.size());
|
||||
EXPECT_EQ(files[0], irs::string_ref("pending_segments_1"));
|
||||
|
||||
writer->commit();
|
||||
|
||||
// create index metadata and read it from the specified directory
|
||||
irs::index_meta meta_read;
|
||||
{
|
||||
std::string segments_file;
|
||||
|
||||
auto reader = codec->get_index_meta_reader();
|
||||
const bool index_exists = reader->last_segments_file(dir, segments_file);
|
||||
|
||||
ASSERT_TRUE(index_exists);
|
||||
reader->read(dir, meta_read, segments_file);
|
||||
}
|
||||
|
||||
EXPECT_EQ(meta_orig.counter(), meta_read.counter());
|
||||
EXPECT_EQ(meta_orig.generation(), meta_read.generation());
|
||||
EXPECT_EQ(meta_orig.size(), meta_read.size());
|
||||
EXPECT_EQ(meta_orig.payload(), meta_read.payload());
|
||||
EXPECT_EQ(meta_orig, meta_read);
|
||||
}
|
||||
|
||||
TEST(index_meta_tests, ctor) {
|
||||
iresearch::index_meta meta;
|
||||
irs::index_meta meta;
|
||||
EXPECT_EQ(0, meta.counter());
|
||||
EXPECT_EQ(0, meta.size());
|
||||
EXPECT_TRUE(meta.payload().null());
|
||||
EXPECT_EQ(irs::type_limits<type_t::index_gen_t>::invalid(), meta.generation());
|
||||
}
|
||||
|
||||
|
|
|
@ -21605,6 +21605,175 @@ INSTANTIATE_TEST_CASE_P(
|
|||
tests::to_string
|
||||
);
|
||||
|
||||
class index_test_case_10 : public tests::index_test_base { };
|
||||
|
||||
TEST_P(index_test_case_10, commit_payload) {
|
||||
tests::json_doc_generator gen(
|
||||
resource("simple_sequential.json"),
|
||||
&tests::generic_json_field_factory);
|
||||
|
||||
auto& directory = dir();
|
||||
auto* doc = gen.next();
|
||||
|
||||
auto writer = open_writer();
|
||||
|
||||
ASSERT_TRUE(writer->begin()); // initial transaction
|
||||
writer->commit();
|
||||
auto reader = irs::directory_reader::open(directory);
|
||||
ASSERT_TRUE(reader.meta().meta.payload().null());
|
||||
|
||||
ASSERT_FALSE(writer->begin()); // transaction hasn't been started, no changes
|
||||
writer->commit();
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
|
||||
// commit with a specified payload
|
||||
{
|
||||
auto payload = irs::ref_cast<irs::byte_type>(irs::string_ref(reader.meta().filename));
|
||||
ASSERT_TRUE(writer->begin(payload)); // different payload supplied
|
||||
writer->commit(irs::bytes_ref::EMPTY); // payload doesn't matter since transaction is already started
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_TRUE(new_reader.meta().meta.payload().null()); // '1_0' doesn't support payload
|
||||
reader = new_reader;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(writer->begin());
|
||||
writer->rollback();
|
||||
|
||||
// commit with empty payload
|
||||
writer->commit(irs::bytes_ref::EMPTY);
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_TRUE(new_reader.meta().meta.payload().null()); // '1_0' doesn't support payload
|
||||
reader = new_reader;
|
||||
}
|
||||
|
||||
ASSERT_FALSE(writer->begin(irs::bytes_ref::EMPTY)); // transaction hasn't been started, no changes
|
||||
writer->commit(irs::bytes_ref::EMPTY);
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
|
||||
// commit without payload
|
||||
writer->commit();
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_TRUE(new_reader.meta().meta.payload().null()); // '1_0' doesn't support payload
|
||||
reader = new_reader;
|
||||
}
|
||||
|
||||
ASSERT_FALSE(writer->begin()); // transaction hasn't been started, no changes
|
||||
writer->commit();
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
index_test_10,
|
||||
index_test_case_10,
|
||||
::testing::Combine(
|
||||
::testing::Values(
|
||||
&tests::memory_directory,
|
||||
&tests::fs_directory,
|
||||
&tests::mmap_directory
|
||||
),
|
||||
::testing::Values("1_0")
|
||||
),
|
||||
tests::to_string
|
||||
);
|
||||
|
||||
class index_test_case_11 : public tests::index_test_base { };
|
||||
|
||||
TEST_P(index_test_case_11, commit_payload) {
|
||||
tests::json_doc_generator gen(
|
||||
resource("simple_sequential.json"),
|
||||
&tests::generic_json_field_factory);
|
||||
|
||||
auto& directory = dir();
|
||||
auto* doc = gen.next();
|
||||
|
||||
auto writer = open_writer();
|
||||
|
||||
ASSERT_TRUE(writer->begin()); // initial transaction
|
||||
writer->commit();
|
||||
auto reader = irs::directory_reader::open(directory);
|
||||
ASSERT_TRUE(reader.meta().meta.payload().null());
|
||||
|
||||
ASSERT_FALSE(writer->begin()); // transaction hasn't been started, no changes
|
||||
writer->commit();
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
|
||||
// commit with a specified payload
|
||||
{
|
||||
auto payload = irs::ref_cast<irs::byte_type>(irs::string_ref(reader.meta().filename));
|
||||
ASSERT_TRUE(writer->begin(payload)); // different payload supplied
|
||||
writer->commit(irs::bytes_ref::EMPTY); // payload doesn't matter since transaction is already started
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_EQ(payload, new_reader.meta().meta.payload());
|
||||
reader = new_reader;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(writer->begin());
|
||||
writer->rollback();
|
||||
|
||||
// commit with empty payload
|
||||
writer->commit(irs::bytes_ref::EMPTY);
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_EQ(irs::bytes_ref::EMPTY, new_reader.meta().meta.payload());
|
||||
ASSERT_TRUE(new_reader.meta().meta.payload().empty());
|
||||
reader = new_reader;
|
||||
}
|
||||
|
||||
ASSERT_FALSE(writer->begin(irs::bytes_ref::EMPTY)); // transaction hasn't been started, no changes
|
||||
writer->commit(irs::bytes_ref::EMPTY);
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
|
||||
// commit without payload
|
||||
writer->commit();
|
||||
|
||||
// check written payload
|
||||
{
|
||||
auto new_reader = reader.reopen();
|
||||
ASSERT_NE(reader, new_reader);
|
||||
ASSERT_TRUE(new_reader.meta().meta.payload().null());
|
||||
reader = new_reader;
|
||||
}
|
||||
|
||||
ASSERT_FALSE(writer->begin()); // transaction hasn't been started, no changes
|
||||
writer->commit();
|
||||
ASSERT_EQ(reader, reader.reopen());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
index_test_11,
|
||||
index_test_case_11,
|
||||
::testing::Combine(
|
||||
::testing::Values(
|
||||
&tests::memory_directory,
|
||||
&tests::fs_directory,
|
||||
&tests::mmap_directory
|
||||
),
|
||||
::testing::Values("1_1")
|
||||
),
|
||||
tests::to_string
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -59,14 +59,14 @@ namespace tests {
|
|||
virtual irs::sort::field_collector::ptr prepare_field_collector() const override {
|
||||
return nullptr; // do not need to collect stats
|
||||
}
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const iresearch::sub_reader&,
|
||||
const iresearch::term_reader&,
|
||||
const irs::byte_type* query_attrs,
|
||||
const irs::attribute_view& doc_attrs,
|
||||
irs::boost_t
|
||||
) const override {
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
virtual irs::sort::term_collector::ptr prepare_term_collector() const override {
|
||||
return nullptr; // do not need to collect stats
|
||||
|
|
|
@ -112,7 +112,7 @@ class all_filter_test_case : public tests::filter_test_case_base {
|
|||
auto& sort = order.add<tests::sort::custom_sort>(false);
|
||||
|
||||
sort.prepare_field_collector_ = []()->irs::sort::field_collector::ptr { return nullptr; };
|
||||
sort.prepare_scorer = [](const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&)->irs::sort::scorer::ptr { return nullptr; };
|
||||
sort.prepare_scorer = [](const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&)->std::pair<irs::sort::score_ctx::ptr, irs::score_f> { return { nullptr, nullptr }; };
|
||||
sort.prepare_term_collector_ = []()->irs::sort::term_collector::ptr { return nullptr; };
|
||||
check_query(irs::all(), order, docs, rdr, false);
|
||||
}
|
||||
|
|
|
@ -54,29 +54,13 @@ struct basic_sort : irs::sort {
|
|||
: irs::sort(basic_sort::type()), idx(idx) {
|
||||
}
|
||||
|
||||
struct basic_scorer : irs::sort::scorer_base<size_t> {
|
||||
struct basic_scorer : irs::sort::score_ctx {
|
||||
explicit basic_scorer(size_t idx) : idx(idx) {}
|
||||
|
||||
void score(irs::byte_type* score) override {
|
||||
score_cast(score) = idx;
|
||||
}
|
||||
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
struct prepared_sort : irs::sort::prepared {
|
||||
template<typename T>
|
||||
FORCE_INLINE static T& score_cast(irs::byte_type* score_buf) {
|
||||
assert(score_buf);
|
||||
return *reinterpret_cast<T*>(score_buf);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FORCE_INLINE static const T& score_cast(const irs::byte_type* score_buf) {
|
||||
assert(score_buf);
|
||||
return *reinterpret_cast<const T*>(score_buf);
|
||||
}
|
||||
|
||||
explicit prepared_sort(size_t idx) : idx(idx) { }
|
||||
|
||||
virtual void collect(
|
||||
|
@ -96,14 +80,20 @@ struct basic_sort : irs::sort {
|
|||
return nullptr; // do not need to collect stats
|
||||
}
|
||||
|
||||
scorer::ptr prepare_scorer(
|
||||
std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const irs::sub_reader&,
|
||||
const irs::term_reader&,
|
||||
const irs::byte_type*,
|
||||
const irs::attribute_view&,
|
||||
irs::boost_t
|
||||
) const override {
|
||||
return scorer::ptr(new basic_scorer(idx));
|
||||
return {
|
||||
score_ctx::ptr(new basic_scorer(idx)),
|
||||
[](const void* ctx, irs::byte_type* score) {
|
||||
auto& state = *reinterpret_cast<const basic_scorer*>(ctx);
|
||||
sort::score_cast<size_t>(score) = state.idx;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void prepare_stats(irs::byte_type*) const override { }
|
||||
|
@ -180,8 +170,9 @@ class basic_doc_iterator: public irs::doc_iterator {
|
|||
boost
|
||||
);
|
||||
|
||||
score_.prepare(ord, [this] (irs::byte_type* score) {
|
||||
scorers_.score(score);
|
||||
score_.prepare(ord, this, [](const void* ctx, irs::byte_type* score) {
|
||||
auto& self = *static_cast<const basic_doc_iterator*>(ctx);
|
||||
self.scorers_.score(score);
|
||||
});
|
||||
|
||||
attrs_.emplace(score_);
|
||||
|
|
|
@ -42,19 +42,12 @@ NS_BEGIN(sort)
|
|||
/// @brief boost scorer assign boost value to the particular document score
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
struct boost : public irs::sort {
|
||||
class scorer: public irs::sort::scorer_base<irs::boost_t> {
|
||||
struct score_ctx: public irs::sort::score_ctx {
|
||||
public:
|
||||
DEFINE_FACTORY_INLINE(scorer)
|
||||
score_ctx(irs::boost_t boost): boost_(boost) { }
|
||||
|
||||
scorer(irs::boost_t boost): boost_(boost) { }
|
||||
|
||||
virtual void score(irs::byte_type* score) {
|
||||
score_cast(score) = boost_;
|
||||
}
|
||||
|
||||
private:
|
||||
irs::boost_t boost_;
|
||||
}; // sort::boost::scorer
|
||||
};
|
||||
|
||||
class prepared: public irs::sort::prepared_basic<irs::boost_t, void> {
|
||||
public:
|
||||
|
@ -65,14 +58,21 @@ struct boost : public irs::sort {
|
|||
return irs::flags::empty_instance();
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<irs::sort::score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const irs::sub_reader&,
|
||||
const irs::term_reader&,
|
||||
const irs::byte_type* query_attrs,
|
||||
const irs::attribute_view& doc_attrs,
|
||||
irs::boost_t boost
|
||||
) const override {
|
||||
return boost::scorer::make<boost::scorer>(boost);
|
||||
return {
|
||||
irs::memory::make_unique<boost::score_ctx>(boost),
|
||||
[](const void* ctx, irs::byte_type* score_buf) {
|
||||
auto& state = *reinterpret_cast<const score_ctx*>(ctx);
|
||||
|
||||
sort::score_cast<irs::boost_t>(score_buf) = state.boost_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -132,19 +132,7 @@ struct custom_sort: public irs::sort {
|
|||
const custom_sort& sort_;
|
||||
};
|
||||
|
||||
class scorer: public irs::sort::scorer_base<irs::doc_id_t> {
|
||||
public:
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
ASSERT_TRUE(score_buf);
|
||||
auto& doc_id = *reinterpret_cast<irs::doc_id_t*>(score_buf);
|
||||
|
||||
doc_id = document_attrs_.get<irs::document>()->value;
|
||||
|
||||
if (sort_.scorer_score) {
|
||||
sort_.scorer_score(doc_id);
|
||||
}
|
||||
}
|
||||
|
||||
struct scorer: public irs::sort::score_ctx {
|
||||
scorer(
|
||||
const custom_sort& sort,
|
||||
const irs::sub_reader& segment_reader,
|
||||
|
@ -158,7 +146,6 @@ struct custom_sort: public irs::sort {
|
|||
term_reader_(term_reader) {
|
||||
}
|
||||
|
||||
private:
|
||||
const irs::attribute_view& document_attrs_;
|
||||
const irs::byte_type* filter_node_attrs_;
|
||||
const irs::sub_reader& segment_reader_;
|
||||
|
@ -194,7 +181,7 @@ struct custom_sort: public irs::sort {
|
|||
return irs::memory::make_unique<collector>(sort_);
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const irs::sub_reader& segment_reader,
|
||||
const irs::term_reader& term_reader,
|
||||
const irs::byte_type* filter_node_attrs,
|
||||
|
@ -207,9 +194,20 @@ struct custom_sort: public irs::sort {
|
|||
);
|
||||
}
|
||||
|
||||
return sort::scorer::make<custom_sort::prepared::scorer>(
|
||||
sort_, segment_reader, term_reader, filter_node_attrs, document_attrs
|
||||
);
|
||||
return {
|
||||
irs::memory::make_unique<custom_sort::prepared::scorer>(sort_, segment_reader, term_reader, filter_node_attrs, document_attrs),
|
||||
[](const void* ctx, irs::byte_type* score_buf) {
|
||||
ASSERT_TRUE(score_buf);
|
||||
auto& state = *reinterpret_cast<const scorer*>(ctx);
|
||||
auto& doc_id = *reinterpret_cast<irs::doc_id_t*>(score_buf);
|
||||
|
||||
doc_id = state.document_attrs_.get<irs::document>()->value;
|
||||
|
||||
if (state.sort_.scorer_score) {
|
||||
state.sort_.scorer_score(doc_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual void prepare_score(irs::byte_type* score) const override {
|
||||
|
@ -242,7 +240,7 @@ struct custom_sort: public irs::sort {
|
|||
std::function<void(const irs::sub_reader&, const irs::term_reader&, const irs::attribute_view&)> collector_collect_term;
|
||||
std::function<void(irs::byte_type*, const irs::index_reader&, const irs::sort::field_collector*, const irs::sort::term_collector*)> collectors_collect_;
|
||||
std::function<irs::sort::field_collector::ptr()> prepare_field_collector_;
|
||||
std::function<scorer::ptr(const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&)> prepare_scorer;
|
||||
std::pair<sort::score_ctx::ptr, irs::score_f>(*prepare_scorer)(const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&){};
|
||||
std::function<irs::sort::term_collector::ptr()> prepare_term_collector_;
|
||||
std::function<void(irs::doc_id_t&, const irs::doc_id_t&)> scorer_add;
|
||||
std::function<bool(const irs::doc_id_t&, const irs::doc_id_t&)> scorer_less;
|
||||
|
@ -295,23 +293,11 @@ struct frequency_sort: public irs::sort {
|
|||
}
|
||||
};
|
||||
|
||||
class scorer: public irs::sort::scorer_base<score_t> {
|
||||
public:
|
||||
struct scorer: public irs::sort::score_ctx {
|
||||
scorer(const size_t* v_docs_count, const irs::attribute_view::ref<irs::document>::type& doc_id_t):
|
||||
doc_id_t_attr(doc_id_t), docs_count(v_docs_count) {
|
||||
}
|
||||
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
auto& buf = score_cast(score_buf);
|
||||
buf.id = doc_id_t_attr->value;
|
||||
|
||||
// docs_count may be nullptr if no collector called, e.g. by range_query for bitset_doc_iterator
|
||||
if (docs_count) {
|
||||
buf.value = 1. / *docs_count;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const irs::attribute_view::ref<irs::document>::type& doc_id_t_attr;
|
||||
const size_t* docs_count;
|
||||
};
|
||||
|
@ -341,7 +327,7 @@ struct frequency_sort: public irs::sort {
|
|||
return nullptr; // do not need to collect stats
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<sort::score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const irs::sub_reader&,
|
||||
const irs::term_reader&,
|
||||
const irs::byte_type* stats_buf,
|
||||
|
@ -351,7 +337,19 @@ struct frequency_sort: public irs::sort {
|
|||
auto& doc_id_t = doc_attrs.get<irs::document>();
|
||||
auto& stats = stats_cast(stats_buf);
|
||||
const size_t* docs_count = &stats.count;
|
||||
return sort::scorer::make<frequency_sort::prepared::scorer>(docs_count, doc_id_t);
|
||||
return {
|
||||
irs::memory::make_unique<frequency_sort::prepared::scorer>(docs_count, doc_id_t),
|
||||
[](const void* ctx, irs::byte_type* score_buf) {
|
||||
auto& state = *reinterpret_cast<const scorer*>(ctx);
|
||||
auto& buf = irs::sort::score_cast<score_t>(score_buf);
|
||||
buf.id = state.doc_id_t_attr->value;
|
||||
|
||||
// docs_count may be nullptr if no collector called, e.g. by range_query for bitset_doc_iterator
|
||||
if (state.docs_count) {
|
||||
buf.value = 1. / *state.docs_count;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual void prepare_score(irs::byte_type* score_buf) const override {
|
||||
|
|
|
@ -59,14 +59,14 @@ struct aligned_scorer : public irs::sort {
|
|||
) const override {
|
||||
// NOOP
|
||||
}
|
||||
virtual scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
const irs::sub_reader& segment,
|
||||
const irs::term_reader& field,
|
||||
const irs::byte_type* stats,
|
||||
const irs::attribute_view& doc_attrs,
|
||||
irs::boost_t boost
|
||||
) const {
|
||||
return nullptr;
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
const irs::flags& features() const {
|
||||
return features_;
|
||||
|
|
|
@ -868,6 +868,7 @@ int search(
|
|||
irs::filter::prepared::ptr filter;
|
||||
std::string tmpBuf;
|
||||
|
||||
#ifdef IRESEARCH_COMPLEX_SCORING
|
||||
#if defined(_MSC_VER) && defined(IRESEARCH_DEBUG)
|
||||
typedef irs::memory::memory_multi_size_pool<irs::memory::identity_grow> pool_t;
|
||||
typedef irs::memory::memory_pool_multi_size_allocator<Entry, pool_t> alloc_t;
|
||||
|
@ -878,7 +879,6 @@ int search(
|
|||
|
||||
pool_t pool(limit + 1); // +1 for least significant overflow element
|
||||
|
||||
#ifdef IRESEARCH_COMPLEX_SCORING
|
||||
auto comparer = [&order](const irs::bstring& lhs, const irs::bstring& rhs)->bool {
|
||||
return order.less(lhs.c_str(), rhs.c_str());
|
||||
};
|
||||
|
@ -886,9 +886,8 @@ int search(
|
|||
comparer, alloc_t{pool}
|
||||
);
|
||||
#else
|
||||
std::multimap<float, irs::doc_id_t, std::less<float>, alloc_t> sorted(
|
||||
std::less<float>(), alloc_t{pool}
|
||||
);
|
||||
std::vector<std::pair<float_t, irs::doc_id_t>> sorted;
|
||||
sorted.reserve(limit + 1); // +1 for least significant overflow element
|
||||
#endif
|
||||
|
||||
// process a single task
|
||||
|
@ -957,13 +956,41 @@ int search(
|
|||
std::forward_as_tuple(raw_score_value),
|
||||
std::forward_as_tuple(docs->value(), score_value)
|
||||
);
|
||||
#else
|
||||
|
||||
sorted.emplace(score_value, doc->value);
|
||||
#endif
|
||||
|
||||
if (sorted.size() > limit) {
|
||||
sorted.erase(--(sorted.end()));
|
||||
}
|
||||
#else
|
||||
std::push_heap(
|
||||
sorted.begin(), sorted.end(),
|
||||
[](const std::pair<float_t, irs::doc_id_t>& lhs,
|
||||
const std::pair<float_t, irs::doc_id_t>& rhs) NOEXCEPT {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
|
||||
if (sorted.size() > limit) {
|
||||
std::pop_heap(
|
||||
sorted.begin(), sorted.end(),
|
||||
[](const std::pair<float_t, irs::doc_id_t>& lhs,
|
||||
const std::pair<float_t, irs::doc_id_t>& rhs) NOEXCEPT {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
|
||||
sorted.pop_back();
|
||||
}
|
||||
|
||||
auto end = sorted.end();
|
||||
for (auto begin = sorted.begin(); begin != end; --end) {
|
||||
std::pop_heap(
|
||||
begin, end,
|
||||
[](const std::pair<float_t, irs::doc_id_t>& lhs,
|
||||
const std::pair<float_t, irs::doc_id_t>& rhs) NOEXCEPT {
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ void IResearchLink::batchInsert( // insert documents
|
|||
}
|
||||
|
||||
if (!queue) {
|
||||
throw std::runtime_error(std::string("failed to report status during batch insert for arangosearch link '") + arangodb::basics::StringUtils::itoa(_id) + "'");
|
||||
throw std::runtime_error("failed to report status during batch insert for arangosearch link '" + arangodb::basics::StringUtils::itoa(_id) + "'");
|
||||
}
|
||||
|
||||
if (!trx.state()) {
|
||||
|
@ -430,8 +430,7 @@ void IResearchLink::batchInsert( // insert documents
|
|||
|
||||
try {
|
||||
for (FieldIterator body(trx); begin != end; ++begin) {
|
||||
auto res =
|
||||
insertDocument(ctx->_ctx, body, begin->second, begin->first, _meta, id());
|
||||
auto res = insertDocument(ctx->_ctx, body, begin->second, begin->first, _meta, id());
|
||||
|
||||
if (!res.ok()) {
|
||||
LOG_TOPIC("e5eb1", WARN, arangodb::iresearch::TOPIC) << res.errorMessage();
|
||||
|
@ -442,17 +441,20 @@ void IResearchLink::batchInsert( // insert documents
|
|||
}
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
LOG_TOPIC("72aa5", WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id() << "': " << e.code() << " " << e.what();
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id()
|
||||
<< "': " << e.code() << " " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
queue->setStatus(e.code());
|
||||
} catch (std::exception const& e) {
|
||||
LOG_TOPIC("3cbae", WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id() << "': " << e.what();
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id()
|
||||
<< "': " << e.what();
|
||||
IR_LOG_EXCEPTION();
|
||||
queue->setStatus(TRI_ERROR_INTERNAL);
|
||||
} catch (...) {
|
||||
LOG_TOPIC("3da8d", WARN, arangodb::iresearch::TOPIC)
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id() << "'";
|
||||
<< "caught exception while inserting batch into arangosearch link '" << id()
|
||||
<< "'";
|
||||
IR_LOG_EXCEPTION();
|
||||
queue->setStatus(TRI_ERROR_INTERNAL);
|
||||
}
|
||||
|
@ -474,15 +476,15 @@ arangodb::Result IResearchLink::cleanupUnsafe() {
|
|||
try {
|
||||
irs::directory_utils::remove_all_unreferenced(*(_dataStore._directory));
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while cleaning up arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "': " + e.what()
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"caught exception while cleaning up arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "': " + e.what());
|
||||
} catch (...) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while cleaning up arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "'"
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"caught exception while cleaning up arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "'");
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
|
@ -498,8 +500,8 @@ arangodb::Result IResearchLink::commit() {
|
|||
if (!*_asyncSelf) {
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_INDEX_HANDLE_BAD, // the current link is no longer valid (checked after ReadLock aquisition)
|
||||
std::string("failed to lock arangosearch link while commiting arangosearch link '") + std::to_string(id()) + "'"
|
||||
);
|
||||
"failed to lock arangosearch link while commiting arangosearch link '"
|
||||
+ std::to_string(id()) + "'");
|
||||
}
|
||||
|
||||
return commitUnsafe();
|
||||
|
@ -523,16 +525,18 @@ arangodb::Result IResearchLink::commitUnsafe() {
|
|||
if (!reader) {
|
||||
// nothing more to do
|
||||
LOG_TOPIC("37bcf", WARN, arangodb::iresearch::TOPIC)
|
||||
<< "failed to update snapshot after commit, run id '" << size_t(&runId) << "', reuse the existing snapshot for arangosearch link '" << id() << "'";
|
||||
<< "failed to update snapshot after commit, run id '" << size_t(&runId)
|
||||
<< "', reuse the existing snapshot for arangosearch link '" << id() << "'";
|
||||
|
||||
return arangodb::Result();
|
||||
}
|
||||
|
||||
if (_dataStore._reader == reader) {
|
||||
// reader not modified
|
||||
if (_dataStore._reader == reader
|
||||
&& _dataStore._recovery_range_start == reader.meta().filename) {
|
||||
|
||||
// reader not modified
|
||||
if (_flushCallback) {
|
||||
//upgrade tick without writing WAL entry
|
||||
// upgrade tick without writing WAL entry
|
||||
return _flushCallback(VPackSlice::noneSlice());
|
||||
}
|
||||
|
||||
|
@ -542,11 +546,8 @@ arangodb::Result IResearchLink::commitUnsafe() {
|
|||
// if WAL 'Flush' recovery is enabled (must be for recoverable DB scenarios)
|
||||
if (_flushCallback && RecoveryState::DONE == _dataStore._recovery) {
|
||||
auto& checkpoint = reader.meta().filename;
|
||||
auto checkpointFile = // checkpoint file name
|
||||
checkpoint + std::string(IRESEARCH_CHECKPOINT_SUFFIX);
|
||||
auto ref = irs::directory_utils::reference( // create a reference
|
||||
*(_dataStore._directory), checkpointFile, true // args
|
||||
);
|
||||
auto checkpointFile = checkpoint + std::string(IRESEARCH_CHECKPOINT_SUFFIX);
|
||||
auto ref = irs::directory_utils::reference(*(_dataStore._directory), checkpointFile, true);
|
||||
arangodb::velocypack::Builder builder;
|
||||
|
||||
builder.add(arangodb::velocypack::Value(checkpoint));
|
||||
|
@ -566,25 +567,26 @@ arangodb::Result IResearchLink::commitUnsafe() {
|
|||
if (!out) { // create checkpoint
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_CANNOT_WRITE_FILE, // code
|
||||
std::string("failed to write checkpoint file for arangosearch link '") + std::to_string(id()) + "', run id '" + std::to_string(size_t(&runId)) + "', ignoring commit success, path: " + checkpointFile
|
||||
);
|
||||
"failed to write checkpoint file for arangosearch link '" + std::to_string(id()) +
|
||||
"', run id '" + std::to_string(size_t(&runId)) +
|
||||
"', ignoring commit success, path: " + checkpointFile);
|
||||
}
|
||||
|
||||
irs::write_string(*out, previousCheckpoint); // will flush on deallocation
|
||||
} catch (std::exception const& e) {
|
||||
_dataStore._directory->remove(checkpointFile); // try to remove failed file
|
||||
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_ARANGO_IO_ERROR, // code
|
||||
std::string("caught exception while writing checkpoint file for arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "': " + e.what()
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_IO_ERROR,
|
||||
"caught exception while writing checkpoint file for arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "': " + e.what());
|
||||
} catch (...) {
|
||||
_dataStore._directory->remove(checkpointFile); // try to remove failed file
|
||||
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_ARANGO_IO_ERROR, // code
|
||||
std::string("caught exception while writing checkpoint file for arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "'"
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_ARANGO_IO_ERROR,
|
||||
"caught exception while writing checkpoint file for arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "'");
|
||||
}
|
||||
|
||||
_dataStore._recovery_range_start = std::move(previousCheckpoint); // remember current checkpoint range start
|
||||
|
@ -593,24 +595,22 @@ arangodb::Result IResearchLink::commitUnsafe() {
|
|||
}
|
||||
|
||||
_dataStore._reader = reader; // update reader
|
||||
arangodb::aql::QueryCache::instance()->invalidate(
|
||||
&(_collection.vocbase()), _viewGuid
|
||||
);
|
||||
arangodb::aql::QueryCache::instance()->invalidate(&(_collection.vocbase()), _viewGuid);
|
||||
} catch (arangodb::basics::Exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
e.code(), // code
|
||||
std::string("caught exception while committing arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "': " + e.what()
|
||||
);
|
||||
return arangodb::Result(
|
||||
e.code(),
|
||||
"caught exception while committing arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "': " + e.what());
|
||||
} catch (std::exception const& e) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while committing arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "': " + e.what()
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"caught exception while committing arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "': " + e.what());
|
||||
} catch (...) {
|
||||
return arangodb::Result( // result
|
||||
TRI_ERROR_INTERNAL, // code
|
||||
std::string("caught exception while committing arangosearch link '") + std::to_string(id()) + "' run id '" + std::to_string(size_t(&runId)) + "'"
|
||||
);
|
||||
return arangodb::Result(
|
||||
TRI_ERROR_INTERNAL,
|
||||
"caught exception while committing arangosearch link '" + std::to_string(id()) +
|
||||
"' run id '" + std::to_string(size_t(&runId)) + "'");
|
||||
}
|
||||
|
||||
return arangodb::Result();
|
||||
|
@ -1111,8 +1111,8 @@ arangodb::Result IResearchLink::initDataStore(InitCallback const& initCallback,
|
|||
|
||||
// if in recovery then recovery markers are expected
|
||||
// if not in recovery then AFTER_CHECKPOINT will be converted to DONE by
|
||||
// the post-recovery-callback (or left untouched if no DatabaseFeature
|
||||
if (engine->inRecovery()) {
|
||||
// the post-recovery-callback (or left untouched if no DatabaseFeature)
|
||||
if (engine->inRecovery() && previousCheckpoint != recovery_reader.meta().filename) {
|
||||
_dataStore._recovery = RecoveryState::DURING_CHECKPOINT; // exisitng data store (assume worst case, i.e. replaying just before checkpoint)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -557,10 +557,8 @@ void registerRecoveryHelper() {
|
|||
}
|
||||
|
||||
res = arangodb::RocksDBEngine::registerRecoveryHelper(
|
||||
std::shared_ptr<RocksDBRecoveryHelper>(
|
||||
const_cast<RocksDBRecoveryHelper*>(&rocksDBHelper),
|
||||
[](RocksDBRecoveryHelper*)->void {}
|
||||
)
|
||||
std::shared_ptr<RocksDBRecoveryHelper>(std::shared_ptr<RocksDBRecoveryHelper>(),
|
||||
const_cast<RocksDBRecoveryHelper*>(&rocksDBHelper))
|
||||
);
|
||||
|
||||
if (!res.ok()) {
|
||||
|
@ -765,8 +763,23 @@ arangodb::Result FlushFeature::releaseUnusedTicks(size_t& count) {
|
|||
TRI_ASSERT(minTick <= engine->currentTick());
|
||||
|
||||
LOG_TOPIC("fd934", TRACE, Logger::FLUSH) << "Releasing tick " << minTick;
|
||||
|
||||
TRI_IF_FAILURE("FlushCrashBeforeSyncingMinTick") {
|
||||
TRI_SegfaultDebugging("crashing before syncing min tick");
|
||||
}
|
||||
|
||||
engine->waitForSyncTick(minTick);
|
||||
|
||||
TRI_IF_FAILURE("FlushCrashAfterSyncingMinTick") {
|
||||
TRI_SegfaultDebugging("crashing after syncing min tick");
|
||||
}
|
||||
|
||||
engine->releaseTick(minTick);
|
||||
|
||||
TRI_IF_FAILURE("FlushCrashAfterReleasingMinTick") {
|
||||
TRI_SegfaultDebugging("crashing after releasing min tick");
|
||||
}
|
||||
|
||||
return Result();
|
||||
}
|
||||
|
||||
|
|
|
@ -52,11 +52,10 @@ void FlushThread::wakeup() {
|
|||
|
||||
/// @brief main loop
|
||||
void FlushThread::run() {
|
||||
FlushFeature* flushFeature =
|
||||
application_features::ApplicationServer::getFeature<FlushFeature>(
|
||||
"Flush");
|
||||
auto* flushFeature =
|
||||
application_features::ApplicationServer::getFeature<FlushFeature>("Flush");
|
||||
|
||||
TRI_ASSERT(flushFeature != nullptr);
|
||||
StorageEngine* engine = EngineSelectorFeature::ENGINE;
|
||||
size_t count = 0;
|
||||
|
||||
while (!isStopping()) {
|
||||
|
@ -68,20 +67,6 @@ void FlushThread::run() {
|
|||
continue;
|
||||
}
|
||||
|
||||
TRI_voc_tick_t toRelease = engine->currentTick();
|
||||
|
||||
LOG_TOPIC("fc0f4", TRACE, Logger::FLUSH)
|
||||
<< "flush thread initiating sync for tick '" << toRelease << "'";
|
||||
engine->waitForSyncTick(toRelease);
|
||||
|
||||
TRI_IF_FAILURE("FlushThreadCrashAfterWalSync") {
|
||||
TRI_SegfaultDebugging("crashing before flush thread callbacks");
|
||||
}
|
||||
|
||||
TRI_IF_FAILURE("FlushThreadCrashAfterCallbacks") {
|
||||
TRI_SegfaultDebugging("crashing before releasing tick");
|
||||
}
|
||||
|
||||
flushFeature->releaseUnusedTicks(count);
|
||||
|
||||
LOG_TOPIC_IF("2b2h1", DEBUG, arangodb::Logger::FLUSH, count)
|
||||
|
|
|
@ -112,22 +112,7 @@ struct custom_sort : public irs::sort {
|
|||
const custom_sort& sort_;
|
||||
};
|
||||
|
||||
class scorer : public irs::sort::scorer_base<irs::doc_id_t> {
|
||||
public:
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
UNUSED(stats_);
|
||||
UNUSED(segment_reader_);
|
||||
UNUSED(term_reader_);
|
||||
EXPECT_TRUE(score_buf);
|
||||
auto& doc_id = *reinterpret_cast<irs::doc_id_t*>(score_buf);
|
||||
|
||||
doc_id = document_attrs_.get<irs::document>()->value;
|
||||
|
||||
if (sort_.scorer_score) {
|
||||
sort_.scorer_score(doc_id);
|
||||
}
|
||||
}
|
||||
|
||||
struct scorer : public irs::sort::score_ctx {
|
||||
scorer(const custom_sort& sort,
|
||||
const irs::sub_reader& segment_reader,
|
||||
const irs::term_reader& term_reader,
|
||||
|
@ -139,7 +124,6 @@ struct custom_sort : public irs::sort {
|
|||
sort_(sort),
|
||||
term_reader_(term_reader) {}
|
||||
|
||||
private:
|
||||
const irs::attribute_view& document_attrs_;
|
||||
const irs::byte_type* stats_;
|
||||
const irs::sub_reader& segment_reader_;
|
||||
|
@ -172,19 +156,35 @@ struct custom_sort : public irs::sort {
|
|||
return irs::memory::make_unique<custom_sort::prepared::collector>(sort_);
|
||||
}
|
||||
|
||||
virtual scorer::ptr prepare_scorer(const irs::sub_reader& segment_reader,
|
||||
const irs::term_reader& term_reader,
|
||||
const irs::byte_type* filter_node_attrs,
|
||||
const irs::attribute_view& document_attrs,
|
||||
irs::boost_t) const override {
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
irs::sub_reader const& segment_reader,
|
||||
irs::term_reader const& term_reader,
|
||||
irs::byte_type const* filter_node_attrs,
|
||||
irs::attribute_view const& document_attrs,
|
||||
irs::boost_t boost) const override {
|
||||
if (sort_.prepare_scorer) {
|
||||
return sort_.prepare_scorer(segment_reader, term_reader,
|
||||
filter_node_attrs, document_attrs);
|
||||
return sort_.prepare_scorer(
|
||||
segment_reader, term_reader,
|
||||
filter_node_attrs, document_attrs, boost);
|
||||
}
|
||||
|
||||
return sort::scorer::make<custom_sort::prepared::scorer>(sort_, segment_reader,
|
||||
term_reader, filter_node_attrs,
|
||||
document_attrs);
|
||||
return {
|
||||
std::make_unique<custom_sort::prepared::scorer>(
|
||||
sort_, segment_reader, term_reader,
|
||||
filter_node_attrs, document_attrs),
|
||||
[](const void* ctx, irs::byte_type* score_buf) {
|
||||
auto& ctxImpl = *reinterpret_cast<const custom_sort::prepared::scorer*>(ctx);
|
||||
|
||||
EXPECT_TRUE(score_buf);
|
||||
auto& doc_id = *reinterpret_cast<irs::doc_id_t*>(score_buf);
|
||||
|
||||
doc_id = ctxImpl.document_attrs_.get<irs::document>()->value;
|
||||
|
||||
if (ctxImpl.sort_.scorer_score) {
|
||||
ctxImpl.sort_.scorer_score(doc_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual irs::sort::term_collector::ptr prepare_term_collector() const override {
|
||||
|
@ -217,7 +217,7 @@ struct custom_sort : public irs::sort {
|
|||
std::function<void(const irs::sub_reader&, const irs::term_reader&, const irs::attribute_view&)> term_collector_collect;
|
||||
std::function<void(irs::byte_type*, const irs::index_reader&)> collector_finish;
|
||||
std::function<irs::sort::field_collector::ptr()> prepare_field_collector;
|
||||
std::function<scorer::ptr(const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&)> prepare_scorer;
|
||||
std::function<std::pair<score_ctx::ptr, irs::score_f>(const irs::sub_reader&, const irs::term_reader&, const irs::byte_type*, const irs::attribute_view&, irs::boost_t)> prepare_scorer;
|
||||
std::function<irs::sort::term_collector::ptr()> prepare_term_collector;
|
||||
std::function<void(irs::doc_id_t&, const irs::doc_id_t&)> scorer_add;
|
||||
std::function<bool(const irs::doc_id_t&, const irs::doc_id_t&)> scorer_less;
|
||||
|
|
|
@ -106,23 +106,25 @@ struct DocIdScorer: public irs::sort {
|
|||
virtual irs::sort::field_collector::ptr prepare_field_collector() const override { return nullptr; }
|
||||
virtual void prepare_score(irs::byte_type* score) const override { }
|
||||
virtual irs::sort::term_collector::ptr prepare_term_collector() const override { return nullptr; }
|
||||
virtual irs::sort::scorer::ptr prepare_scorer(
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
irs::sub_reader const& segment,
|
||||
irs::term_reader const& field,
|
||||
irs::byte_type const*,
|
||||
irs::attribute_view const& doc_attrs,
|
||||
irs::boost_t
|
||||
) const override {
|
||||
return irs::sort::scorer::make<Scorer>(doc_attrs.get<irs::document>());
|
||||
return {
|
||||
std::make_unique<ScoreCtx>(doc_attrs.get<irs::document>()),
|
||||
[](const void* ctx, irs::byte_type* score_buf) {
|
||||
reinterpret_cast<uint64_t&>(*score_buf) = reinterpret_cast<const ScoreCtx*>(ctx)->_doc.get()->value;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct Scorer: public irs::sort::scorer {
|
||||
struct ScoreCtx: public irs::sort::score_ctx {
|
||||
ScoreCtx(irs::attribute_view::ref<irs::document>::type const& doc): _doc(doc) { }
|
||||
irs::attribute_view::ref<irs::document>::type const& _doc;
|
||||
Scorer(irs::attribute_view::ref<irs::document>::type const& doc): _doc(doc) { }
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
reinterpret_cast<uint64_t&>(*score_buf) = _doc.get()->value;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -102,22 +102,25 @@ struct BoostScorer : public irs::sort {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual irs::sort::scorer::ptr prepare_scorer(irs::sub_reader const&,
|
||||
irs::term_reader const&,
|
||||
irs::byte_type const*,
|
||||
irs::attribute_view const&,
|
||||
irs::boost_t boost) const override {
|
||||
struct Scorer : public irs::sort::scorer {
|
||||
Scorer(irs::boost_t score) : scr(score) {}
|
||||
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
*reinterpret_cast<score_t*>(score_buf) = scr;
|
||||
}
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
irs::sub_reader const&,
|
||||
irs::term_reader const&,
|
||||
irs::byte_type const*,
|
||||
irs::attribute_view const&,
|
||||
irs::boost_t boost) const override {
|
||||
struct ScoreCtx : public irs::sort::score_ctx {
|
||||
ScoreCtx(irs::boost_t score) : scr(score) {}
|
||||
|
||||
irs::boost_t scr;
|
||||
};
|
||||
|
||||
return irs::sort::scorer::make<Scorer>(boost);
|
||||
return {
|
||||
std::make_unique<ScoreCtx>(boost),
|
||||
[](const void* ctx, irs::byte_type* score_buf) noexcept {
|
||||
auto& state = *static_cast<const ScoreCtx*>(ctx);
|
||||
irs::sort::score_cast<irs::boost_t>(score_buf) = state.scr;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,22 +180,25 @@ struct CustomScorer : public irs::sort {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
virtual irs::sort::scorer::ptr prepare_scorer(irs::sub_reader const&,
|
||||
irs::term_reader const&,
|
||||
irs::byte_type const*,
|
||||
irs::attribute_view const&,
|
||||
irs::boost_t) const override {
|
||||
struct Scorer : public irs::sort::scorer {
|
||||
Scorer(float_t score) : i(score) {}
|
||||
|
||||
virtual void score(irs::byte_type* score_buf) override {
|
||||
*reinterpret_cast<score_t*>(score_buf) = i;
|
||||
}
|
||||
virtual std::pair<score_ctx::ptr, irs::score_f> prepare_scorer(
|
||||
irs::sub_reader const&,
|
||||
irs::term_reader const&,
|
||||
irs::byte_type const*,
|
||||
irs::attribute_view const&,
|
||||
irs::boost_t) const override {
|
||||
struct ScoreCtx : public irs::sort::score_ctx {
|
||||
ScoreCtx(float_t score) : i(score) {}
|
||||
|
||||
float_t i;
|
||||
};
|
||||
|
||||
return irs::sort::scorer::make<Scorer>(i);
|
||||
return {
|
||||
std::make_unique<ScoreCtx>(i),
|
||||
[](const void* ctx, irs::byte_type* score_buf) noexcept {
|
||||
auto& state = *static_cast<const ScoreCtx*>(ctx);
|
||||
irs::sort::score_cast<float_t>(score_buf) = state.i;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
float_t i;
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* jshint globalstrict:false, strict:false, unused : false */
|
||||
/* global assertEqual, assertTrue, assertFalse, assertNull, fail, AQL_EXECUTE */
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief recovery tests for views
|
||||
// /
|
||||
// / @file
|
||||
// /
|
||||
// / DISCLAIMER
|
||||
// /
|
||||
// / Copyright 2010-2012 triagens 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 triAGENS GmbH, Cologne, Germany
|
||||
// /
|
||||
// / @author Jan Steemann
|
||||
// / @author Copyright 2013, triAGENS GmbH, Cologne, Germany
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var db = require('@arangodb').db;
|
||||
var internal = require('internal');
|
||||
var jsunity = require('jsunity');
|
||||
|
||||
function runSetup () {
|
||||
'use strict';
|
||||
internal.debugClearFailAt();
|
||||
|
||||
db._drop('UnitTestsRecoveryDummy');
|
||||
var c = db._create('UnitTestsRecoveryDummy');
|
||||
|
||||
db._dropView('UnitTestsRecoveryView');
|
||||
db._createView('UnitTestsRecoveryView', 'arangosearch', {});
|
||||
|
||||
var meta = { links: { 'UnitTestsRecoveryDummy': { includeAllFields: true } } };
|
||||
db._view('UnitTestsRecoveryView').properties(meta);
|
||||
|
||||
internal.wal.flush(true, true);
|
||||
internal.debugSetFailAt("FlushCrashAfterReleasingMinTick");
|
||||
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
c.save({ a: "foo_" + i, b: "bar_" + i, c: i });
|
||||
}
|
||||
|
||||
c.save({ name: 'crashme' }, { waitForSync: true });
|
||||
|
||||
internal.debugSegfault('crashing server');
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief test suite
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function recoverySuite () {
|
||||
'use strict';
|
||||
jsunity.jsUnity.attachAssertions();
|
||||
|
||||
return {
|
||||
setUp: function () {},
|
||||
tearDown: function () {},
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief test whether we can restore the trx data
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testIResearchLinkPopulateNoRelease: function () {
|
||||
var v = db._view('UnitTestsRecoveryView');
|
||||
assertEqual(v.name(), 'UnitTestsRecoveryView');
|
||||
assertEqual(v.type(), 'arangosearch');
|
||||
var p = v.properties().links;
|
||||
assertTrue(p.hasOwnProperty('UnitTestsRecoveryDummy'));
|
||||
assertTrue(p.UnitTestsRecoveryDummy.includeAllFields);
|
||||
|
||||
var result = AQL_EXECUTE("FOR doc IN UnitTestsRecoveryView SEARCH doc.c >= 0 OPTIONS {waitForSync: true} COLLECT WITH COUNT INTO length RETURN length").json;
|
||||
assertTrue(result[0] > 0);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief executes the test suite
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function main (argv) {
|
||||
'use strict';
|
||||
if (argv[1] === 'setup') {
|
||||
runSetup();
|
||||
return 0;
|
||||
} else {
|
||||
jsunity.run(recoverySuite);
|
||||
return jsunity.writeDone().status ? 0 : 1;
|
||||
}
|
||||
}
|
|
@ -45,9 +45,9 @@ function runSetup () {
|
|||
db._view('UnitTestsRecoveryView').properties(meta);
|
||||
|
||||
internal.wal.flush(true, true);
|
||||
internal.debugSetFailAt("FlushThreadCrashAfterWalSync");
|
||||
internal.debugSetFailAt("FlushCrashAfterSyncingMinTick");
|
||||
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
for (let i = 0; i < 100000; i++) {
|
||||
c.save({ a: "foo_" + i, b: "bar_" + i, c: i });
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ function runSetup () {
|
|||
db._view('UnitTestsRecoveryView').properties(meta);
|
||||
|
||||
internal.wal.flush(true, true);
|
||||
internal.debugSetFailAt("FlushThreadCrashAfterCallbacks");
|
||||
internal.debugSetFailAt("FlushCrashAfterSyncingMinTick");
|
||||
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
c.save({ a: "foo_" + i, b: "bar_" + i, c: i });
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* jshint globalstrict:false, strict:false, unused : false */
|
||||
/* global assertEqual, assertTrue, assertFalse, assertNull, fail, AQL_EXECUTE */
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief recovery tests for views
|
||||
// /
|
||||
// / @file
|
||||
// /
|
||||
// / DISCLAIMER
|
||||
// /
|
||||
// / Copyright 2010-2012 triagens 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 triAGENS GmbH, Cologne, Germany
|
||||
// /
|
||||
// / @author Jan Steemann
|
||||
// / @author Copyright 2013, triAGENS GmbH, Cologne, Germany
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var db = require('@arangodb').db;
|
||||
var internal = require('internal');
|
||||
var jsunity = require('jsunity');
|
||||
|
||||
function runSetup () {
|
||||
'use strict';
|
||||
internal.debugClearFailAt();
|
||||
|
||||
db._drop('UnitTestsRecoveryDummy');
|
||||
var c = db._create('UnitTestsRecoveryDummy');
|
||||
|
||||
db._dropView('UnitTestsRecoveryView');
|
||||
db._createView('UnitTestsRecoveryView', 'arangosearch', {});
|
||||
|
||||
var meta = { links: { 'UnitTestsRecoveryDummy': { includeAllFields: true } } };
|
||||
db._view('UnitTestsRecoveryView').properties(meta);
|
||||
|
||||
internal.wal.flush(true, true);
|
||||
internal.debugSetFailAt("FlushCrashBeforeSyncingMinTick");
|
||||
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
c.save({ a: "foo_" + i, b: "bar_" + i, c: i });
|
||||
}
|
||||
|
||||
c.save({ name: 'crashme' }, { waitForSync: true });
|
||||
|
||||
internal.debugSegfault('crashing server');
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief test suite
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function recoverySuite () {
|
||||
'use strict';
|
||||
jsunity.jsUnity.attachAssertions();
|
||||
|
||||
return {
|
||||
setUp: function () {},
|
||||
tearDown: function () {},
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief test whether we can restore the trx data
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testIResearchLinkPopulateNoRelease: function () {
|
||||
var v = db._view('UnitTestsRecoveryView');
|
||||
assertEqual(v.name(), 'UnitTestsRecoveryView');
|
||||
assertEqual(v.type(), 'arangosearch');
|
||||
var p = v.properties().links;
|
||||
assertTrue(p.hasOwnProperty('UnitTestsRecoveryDummy'));
|
||||
assertTrue(p.UnitTestsRecoveryDummy.includeAllFields);
|
||||
|
||||
var result = AQL_EXECUTE("FOR doc IN UnitTestsRecoveryView SEARCH doc.c >= 0 OPTIONS {waitForSync: true} COLLECT WITH COUNT INTO length RETURN length").json;
|
||||
assertTrue(result[0] > 0);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// / @brief executes the test suite
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function main (argv) {
|
||||
'use strict';
|
||||
if (argv[1] === 'setup') {
|
||||
runSetup();
|
||||
return 0;
|
||||
} else {
|
||||
jsunity.run(recoverySuite);
|
||||
return jsunity.writeDone().status ? 0 : 1;
|
||||
}
|
||||
}
|
|
@ -44,14 +44,13 @@ function runSetup () {
|
|||
var meta = { links: { 'UnitTestsRecoveryDummy': { includeAllFields: true } } };
|
||||
db._view('UnitTestsRecoveryView').properties(meta);
|
||||
|
||||
// FIXME uncomment when we'll be able to handle tons of removals properly
|
||||
// for (let i = 0; i < 20000; i++) {
|
||||
// c.save({ a: "foo_" + i, b: "bar_" + i, c: i, _key: "doc_" + i });
|
||||
// }
|
||||
//
|
||||
// for (let i = 10000; i < 20000; i++) {
|
||||
// c.remove("doc_" + i);
|
||||
// }
|
||||
for (let i = 0; i < 20000; i++) {
|
||||
c.save({ a: "foo_" + i, b: "bar_" + i, c: i, _key: "doc_" + i });
|
||||
}
|
||||
|
||||
for (let i = 10000; i < 20000; i++) {
|
||||
c.remove("doc_" + i);
|
||||
}
|
||||
|
||||
c.save({ name: "crashme" }, { waitForSync: true });
|
||||
|
||||
|
@ -82,9 +81,8 @@ function recoverySuite () {
|
|||
assertTrue(p.hasOwnProperty('UnitTestsRecoveryDummy'));
|
||||
assertTrue(p.UnitTestsRecoveryDummy.includeAllFields);
|
||||
|
||||
// FIXME uncomment when we'll be able to handle tons of removals properly
|
||||
// var result = AQL_EXECUTE("FOR doc IN UnitTestsRecoveryView SEARCH doc.c >= 0 OPTIONS {waitForSync: true} COLLECT WITH COUNT INTO length RETURN length").json;
|
||||
// assertEqual(result[0], 10000);
|
||||
var result = AQL_EXECUTE("FOR doc IN UnitTestsRecoveryView SEARCH doc.c >= 0 OPTIONS {waitForSync: true} COLLECT WITH COUNT INTO length RETURN length").json;
|
||||
assertEqual(result[0], 10000);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue