Packages
rocksdb
2.3.0
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
c_src/bitset_merge_operator.cc
// Copyright (c) 2018-2025 Benoit Chesneau
//
// This file is provided to you 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.
#include <string>
#include <memory>
#include <list>
#include <algorithm>
#include <assert.h>
#include "rocksdb/slice.h"
#include "rocksdb/merge_operator.h"
#include "erl_nif.h"
#include "util.h"
#include "bitset_merge_operator.h"
static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
static const unsigned char bit_mask[bits_per_char] = {
0x80, //10000000
0x40, //01000000
0x20, //00100000
0x10, //00010000
0x08, //00001000
0x04, //00000100
0x02, //00000010
0x01 //00000001
};
namespace erocksdb {
BitsetMergeOperator::BitsetMergeOperator(unsigned int cap)
:cap_(cap) {
}
bool BitsetMergeOperator::FullMergeV2(
const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const {
size_t size;
char* data = nullptr;
std::string s;
int pos;
size_t max_size = cap_ / bits_per_char;
if (!merge_in.existing_value) {
size = max_size;
merge_out->new_value.reserve(size);
data = new cell_type[size];
std::fill_n(data, size, 0x00);
} else {
size = merge_in.existing_value->size();
if (size < max_size)
return false;
data = const_cast<char*>(merge_in.existing_value->data());
}
auto it = merge_in.operand_list.begin();
while (it != merge_in.operand_list.end()) {
s = it->ToString();
if (s.empty()) {
std::fill_n(data, size, 0x00);
++it;
continue;
}
try {
pos = std::stoi(s.substr(1));
} catch(...) {
if (!merge_in.existing_value) {
delete[] data;
}
return false;
}
size_t ofs = pos >> 3;
if (ofs > size) {
if (!merge_in.existing_value) {
delete[] data;
}
return false;
}
//char bytemask = (1 << ((1 << 3)) - (pos & ((1 << 3)))));
if (s[0] == '+') {
//data[(pos >> 3)] |= bytemask;
data[ofs] |= bit_mask[pos % bits_per_char];
} else if (s[0] == '-') {
//data[(pos >> 3)] &= ~bytemask;
data[ofs] &= ~bit_mask[pos % bits_per_char];
} else {
if (!merge_in.existing_value) {
delete[] data;
}
return false;
}
++it;
}
//clear the new value for writing
merge_out->new_value.clear();
merge_out->new_value.append(reinterpret_cast<char*>(data), size);
if (!merge_in.existing_value) {
delete[] data;
}
return true;
}
bool BitsetMergeOperator::PartialMergeMulti(
const rocksdb::Slice& /*key*/,
const std::deque<rocksdb::Slice>& /*operand_list*/,
std::string* /*new_value*/,
rocksdb::Logger* /*logger*/) const {
return false;
}
const char* BitsetMergeOperator::Name() const {
return "BitsetMergeOperator";
}
std::shared_ptr<BitsetMergeOperator> CreateBitsetMergeOperator(unsigned int cap) {
return std::make_shared<BitsetMergeOperator>(cap);
}
}