1
0
Fork 0
arangodb/arangod/MMFiles/MMFilesIndexElement.h

284 lines
10 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_MMFILES_INDEX_ELEMENT_H
#define ARANGOD_MMFILES_INDEX_ELEMENT_H 1
#include "Basics/Common.h"
#include "VocBase/LocalDocumentId.h"
#include "VocBase/voc-types.h"
#include "VocBase/vocbase.h"
namespace arangodb {
class IndexLookupContext;
namespace velocypack {
class Slice;
}
/// @brief velocypack sub-object (for indexes, as part of IndexElement,
/// if the last byte in data[] is 0, then the VelocyPack data is managed
/// by the datafile the element is in. If the last byte in data[] is 1, then
/// value.data contains the actual VelocyPack data in place.
struct MMFilesIndexElementValue {
friend struct MMFilesHashIndexElement;
friend struct MMFilesSkiplistIndexElement;
public:
MMFilesIndexElementValue() {}
~MMFilesIndexElementValue() {}
/// @brief fill an MMFilesIndexElementValue structure with a subvalue
void fill(velocypack::Slice const value, uint32_t offset) {
velocypack::ValueLength len = value.byteSize();
if (len <= maxValueLength()) {
setInline(value.start(), static_cast<size_t>(len));
} else {
setOffset(offset);
}
}
/// @brief velocypack sub-object (for indexes, as part of IndexElement,
/// if offset is non-zero, then it is an offset into the VelocyPack data in
/// the data or WAL file. If offset is 0, then data contains the actual data
/// in place.
velocypack::Slice slice(IndexLookupContext* context) const;
inline bool isOffset() const noexcept { return !isInline(); }
inline bool isInline() const noexcept {
return value.data[maxValueLength()] == 1;
}
private:
void setOffset(uint32_t offset) {
value.offset = offset;
value.data[maxValueLength()] = 0; // type = offset
}
void setInline(uint8_t const* data, size_t length) noexcept {
TRI_ASSERT(length > 0);
TRI_ASSERT(length <= maxValueLength());
memcpy(&value.data[0], data, length);
value.data[maxValueLength()] = 1; // type = inline
}
static constexpr size_t maxValueLength() noexcept {
return sizeof(value.data) - 1;
}
private:
union {
uint8_t data[12];
uint32_t offset;
} value;
};
static_assert(sizeof(MMFilesIndexElementValue) == 12,
"invalid size of MMFilesIndexElementValue");
/// @brief hash index element. Do not directly construct it.
struct MMFilesHashIndexElement {
// Do not use new for this struct, use create()!
private:
MMFilesHashIndexElement(LocalDocumentId const& documentId,
std::vector<std::pair<arangodb::velocypack::Slice, uint32_t>> const& values);
MMFilesHashIndexElement() = delete;
MMFilesHashIndexElement(MMFilesHashIndexElement const&) = delete;
MMFilesHashIndexElement& operator=(MMFilesHashIndexElement const&) = delete;
~MMFilesHashIndexElement() = delete;
public:
inline bool isSet() const { return _localDocumentId.isSet(); }
/// @brief get the local document id
inline LocalDocumentId localDocumentId() const { return _localDocumentId; }
inline LocalDocumentId::BaseType localDocumentIdValue() const {
return _localDocumentId.id();
}
inline uint64_t hash() const { return _hash & 0xFFFFFFFFULL; }
inline operator bool() const { return _localDocumentId.isSet(); }
inline bool operator==(MMFilesHashIndexElement const& other) const {
return _localDocumentId == other._localDocumentId && _hash == other._hash;
}
inline bool operator<(MMFilesHashIndexElement const& other) const {
return _localDocumentId < other._localDocumentId;
}
/// @brief base memory usage of an index element
static constexpr size_t baseMemoryUsage(size_t numSubs) {
return sizeof(LocalDocumentId) + sizeof(uint32_t) +
(sizeof(MMFilesIndexElementValue) * numSubs);
}
inline MMFilesIndexElementValue const* subObject(size_t position) const {
char const* p = reinterpret_cast<char const*>(this) + baseMemoryUsage(position);
return reinterpret_cast<MMFilesIndexElementValue const*>(p);
}
arangodb::velocypack::Slice slice(IndexLookupContext* context, size_t position) const;
static uint64_t hash(arangodb::velocypack::Slice const& values);
static uint64_t hash(std::vector<arangodb::velocypack::Slice> const& values);
static uint64_t hash(std::vector<std::pair<arangodb::velocypack::Slice, uint32_t>> const& values);
/// @brief allocate a new index element from a vector of slices
static MMFilesHashIndexElement* initialize(
MMFilesHashIndexElement* memory, LocalDocumentId const& localDocumentId,
std::vector<std::pair<arangodb::velocypack::Slice, uint32_t>> const& values);
private:
inline MMFilesIndexElementValue* subObject(size_t position) {
char* p = reinterpret_cast<char*>(this) + sizeof(LocalDocumentId) +
sizeof(uint32_t) + (sizeof(MMFilesIndexElementValue) * position);
return reinterpret_cast<MMFilesIndexElementValue*>(p);
}
private:
LocalDocumentId _localDocumentId;
uint32_t _hash;
};
/// @brief skiplist index element. Do not directly construct it.
struct MMFilesSkiplistIndexElement {
// Do not use new for this struct, use create()!
private:
MMFilesSkiplistIndexElement(LocalDocumentId const& documentId,
std::vector<std::pair<arangodb::velocypack::Slice, uint32_t>> const& values);
MMFilesSkiplistIndexElement() = delete;
MMFilesSkiplistIndexElement(MMFilesSkiplistIndexElement const&) = delete;
MMFilesSkiplistIndexElement& operator=(MMFilesSkiplistIndexElement const&) = delete;
~MMFilesSkiplistIndexElement() = delete;
public:
inline bool isSet() const { return _localDocumentId.isSet(); }
/// @brief get the local document id
inline LocalDocumentId localDocumentId() const { return _localDocumentId; }
inline LocalDocumentId::BaseType localDocumentIdValue() const {
return _localDocumentId.id();
}
inline operator bool() const { return _localDocumentId.isSet(); }
inline bool operator==(MMFilesSkiplistIndexElement const& other) const {
return _localDocumentId == other._localDocumentId;
}
/// @brief base memory usage of an index element
static constexpr size_t baseMemoryUsage(size_t numSubs) {
return sizeof(LocalDocumentId) + (sizeof(MMFilesIndexElementValue) * numSubs);
}
inline MMFilesIndexElementValue const* subObject(size_t position) const {
char const* p = reinterpret_cast<char const*>(this) + baseMemoryUsage(position);
return reinterpret_cast<MMFilesIndexElementValue const*>(p);
}
arangodb::velocypack::Slice slice(IndexLookupContext* context, size_t position) const;
/// @brief allocate a new index element from a vector of slices
static MMFilesSkiplistIndexElement* initialize(
MMFilesSkiplistIndexElement* element, LocalDocumentId const& documentId,
std::vector<std::pair<arangodb::velocypack::Slice, uint32_t>> const& values);
private:
inline MMFilesIndexElementValue* subObject(size_t position) {
char* p = reinterpret_cast<char*>(this) + sizeof(LocalDocumentId) +
(sizeof(MMFilesIndexElementValue) * position);
return reinterpret_cast<MMFilesIndexElementValue*>(p);
}
private:
LocalDocumentId _localDocumentId;
};
struct MMFilesSimpleIndexElement {
public:
// clang does not like:
// constexpr MMFilesSimpleIndexElement() : _localDocumentId(LocalDocumentId::none()), _hashAndOffset(0) {}
MMFilesSimpleIndexElement()
: _localDocumentId(LocalDocumentId::none()), _hashAndOffset(0) {}
MMFilesSimpleIndexElement(LocalDocumentId const& documentId,
arangodb::velocypack::Slice const& value, uint32_t offset);
MMFilesSimpleIndexElement(MMFilesSimpleIndexElement const& other) noexcept
: _localDocumentId(other._localDocumentId),
_hashAndOffset(other._hashAndOffset) {}
MMFilesSimpleIndexElement& operator=(MMFilesSimpleIndexElement const& other) noexcept {
_localDocumentId = other._localDocumentId;
_hashAndOffset = other._hashAndOffset;
return *this;
}
inline bool isSet() const { return _localDocumentId.isSet(); }
/// @brief get the local document id
inline LocalDocumentId localDocumentId() const { return _localDocumentId; }
inline LocalDocumentId::BaseType localDocumentIdValue() const {
return _localDocumentId.id();
}
inline uint64_t hash() const noexcept {
return _hashAndOffset & 0xFFFFFFFFULL;
}
inline uint32_t offset() const noexcept {
return static_cast<uint32_t>((_hashAndOffset & 0xFFFFFFFF00000000ULL) >> 32);
}
arangodb::velocypack::Slice slice(IndexLookupContext*) const;
inline operator bool() const noexcept { return _localDocumentId.isSet(); }
inline bool operator==(MMFilesSimpleIndexElement const& other) const noexcept {
return _localDocumentId == other._localDocumentId && _hashAndOffset == other._hashAndOffset;
}
inline bool operator<(MMFilesSimpleIndexElement const& other) const noexcept {
return _localDocumentId < other._localDocumentId;
}
static uint64_t hash(arangodb::velocypack::Slice const& value);
inline void updateLocalDocumentId(LocalDocumentId const& documentId, uint32_t offset) {
_localDocumentId = documentId;
_hashAndOffset &= 0xFFFFFFFFULL;
_hashAndOffset |= (static_cast<uint64_t>(offset) << 32);
}
private:
LocalDocumentId _localDocumentId;
uint64_t _hashAndOffset;
};
} // namespace arangodb
#endif