removed copy of zano
This commit is contained in:
parent
20029ddb13
commit
3bee4d9855
1154 changed files with 0 additions and 291257 deletions
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive, class value_t>
|
||||
inline void save(Archive &a, const std::atomic<value_t> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a << x.load();
|
||||
}
|
||||
|
||||
template <class Archive, class value_t>
|
||||
inline void load(Archive &a, std::atomic<value_t> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
value_t s = AUTO_VAL_INIT(s);
|
||||
a >> s;
|
||||
x.store(s);
|
||||
}
|
||||
template <class Archive, class value_t>
|
||||
inline void serialize(Archive &a, std::atomic<value_t> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "int-util.h"
|
||||
#include "util.h"
|
||||
#include "varint.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace base58
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
const size_t alphabet_size = sizeof(alphabet) - 1;
|
||||
const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11};
|
||||
const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1;
|
||||
const size_t full_encoded_block_size = encoded_block_sizes[full_block_size];
|
||||
const size_t addr_checksum_size = 4;
|
||||
|
||||
struct reverse_alphabet
|
||||
{
|
||||
reverse_alphabet()
|
||||
{
|
||||
m_data.resize(alphabet[alphabet_size - 1] - alphabet[0] + 1, -1);
|
||||
|
||||
for (size_t i = 0; i < alphabet_size; ++i)
|
||||
{
|
||||
size_t idx = static_cast<size_t>(alphabet[i] - alphabet[0]);
|
||||
m_data[idx] = static_cast<int8_t>(i);
|
||||
}
|
||||
}
|
||||
|
||||
int operator()(char letter) const
|
||||
{
|
||||
size_t idx = static_cast<size_t>(letter - alphabet[0]);
|
||||
return idx < m_data.size() ? m_data[idx] : -1;
|
||||
}
|
||||
|
||||
static reverse_alphabet instance;
|
||||
|
||||
private:
|
||||
std::vector<int8_t> m_data;
|
||||
};
|
||||
|
||||
reverse_alphabet reverse_alphabet::instance;
|
||||
|
||||
struct decoded_block_sizes
|
||||
{
|
||||
decoded_block_sizes()
|
||||
{
|
||||
m_data.resize(encoded_block_sizes[full_block_size] + 1, -1);
|
||||
for (size_t i = 0; i <= full_block_size; ++i)
|
||||
{
|
||||
m_data[encoded_block_sizes[i]] = static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
|
||||
int operator()(size_t encoded_block_size) const
|
||||
{
|
||||
assert(encoded_block_size <= full_encoded_block_size);
|
||||
return m_data[encoded_block_size];
|
||||
}
|
||||
|
||||
static decoded_block_sizes instance;
|
||||
|
||||
private:
|
||||
std::vector<int> m_data;
|
||||
};
|
||||
|
||||
decoded_block_sizes decoded_block_sizes::instance;
|
||||
|
||||
uint64_t uint_8be_to_64(const uint8_t* data, size_t size)
|
||||
{
|
||||
assert(1 <= size && size <= sizeof(uint64_t));
|
||||
|
||||
uint64_t res = 0;
|
||||
switch (9 - size)
|
||||
{
|
||||
case 1: res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 2: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 3: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 4: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 5: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 6: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 7: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 8: res <<= 8; res |= *data; break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data)
|
||||
{
|
||||
assert(1 <= size && size <= sizeof(uint64_t));
|
||||
|
||||
uint64_t num_be = SWAP64BE(num);
|
||||
memcpy(data, reinterpret_cast<uint8_t*>(&num_be) + sizeof(uint64_t) - size, size);
|
||||
}
|
||||
|
||||
void encode_block(const char* block, size_t size, char* res)
|
||||
{
|
||||
assert(1 <= size && size <= full_block_size);
|
||||
|
||||
uint64_t num = uint_8be_to_64(reinterpret_cast<const uint8_t*>(block), size);
|
||||
int i = static_cast<int>(encoded_block_sizes[size]) - 1;
|
||||
while (0 < num)
|
||||
{
|
||||
uint64_t remainder = num % alphabet_size;
|
||||
num /= alphabet_size;
|
||||
res[i] = alphabet[remainder];
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
bool decode_block(const char* block, size_t size, char* res)
|
||||
{
|
||||
assert(1 <= size && size <= full_encoded_block_size);
|
||||
|
||||
int res_size = decoded_block_sizes::instance(size);
|
||||
if (res_size <= 0)
|
||||
return false; // Invalid block size
|
||||
|
||||
uint64_t res_num = 0;
|
||||
uint64_t order = 1;
|
||||
for (size_t i = size - 1; i < size; --i)
|
||||
{
|
||||
int digit = reverse_alphabet::instance(block[i]);
|
||||
if (digit < 0)
|
||||
return false; // Invalid symbol
|
||||
|
||||
//uint64_t product_hi;
|
||||
boost::multiprecision::uint128_t tmp = res_num;
|
||||
tmp += boost::multiprecision::uint128_t(order) * digit;
|
||||
|
||||
if (tmp < res_num || tmp > std::numeric_limits<uint64_t>::max() )
|
||||
return false; // Overflow
|
||||
|
||||
res_num = tmp.convert_to<uint64_t>();
|
||||
order *= alphabet_size; // Never overflows, 58^10 < 2^64
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(res_size) < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num)
|
||||
return false; // Overflow
|
||||
|
||||
uint_64_to_8be(res_num, res_size, reinterpret_cast<uint8_t*>(res));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string encode(const std::string& data)
|
||||
{
|
||||
if (data.empty())
|
||||
return std::string();
|
||||
|
||||
size_t full_block_count = data.size() / full_block_size;
|
||||
size_t last_block_size = data.size() % full_block_size;
|
||||
size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size];
|
||||
|
||||
std::string res(res_size, alphabet[0]);
|
||||
for (size_t i = 0; i < full_block_count; ++i)
|
||||
{
|
||||
encode_block(data.data() + i * full_block_size, full_block_size, &res[i * full_encoded_block_size]);
|
||||
}
|
||||
|
||||
if (0 < last_block_size)
|
||||
{
|
||||
encode_block(data.data() + full_block_count * full_block_size, last_block_size, &res[full_block_count * full_encoded_block_size]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool decode(const std::string& enc, std::string& data)
|
||||
{
|
||||
if (enc.empty())
|
||||
{
|
||||
data.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t full_block_count = enc.size() / full_encoded_block_size;
|
||||
size_t last_block_size = enc.size() % full_encoded_block_size;
|
||||
int last_block_decoded_size = decoded_block_sizes::instance(last_block_size);
|
||||
if (last_block_decoded_size < 0)
|
||||
return false; // Invalid enc length
|
||||
size_t data_size = full_block_count * full_block_size + last_block_decoded_size;
|
||||
|
||||
data.resize(data_size, 0);
|
||||
for (size_t i = 0; i < full_block_count; ++i)
|
||||
{
|
||||
if (!decode_block(enc.data() + i * full_encoded_block_size, full_encoded_block_size, &data[i * full_block_size]))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 < last_block_size)
|
||||
{
|
||||
if (!decode_block(enc.data() + full_block_count * full_encoded_block_size, last_block_size,
|
||||
&data[full_block_count * full_block_size]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string encode_addr(uint64_t tag, const std::string& data)
|
||||
{
|
||||
std::string buf = get_varint_data(tag);
|
||||
buf += data;
|
||||
crypto::hash hash = crypto::cn_fast_hash(buf.data(), buf.size());
|
||||
const char* hash_data = reinterpret_cast<const char*>(&hash);
|
||||
buf.append(hash_data, addr_checksum_size);
|
||||
return encode(buf);
|
||||
}
|
||||
|
||||
bool decode_addr(std::string addr, uint64_t& tag, std::string& data)
|
||||
{
|
||||
std::string addr_data;
|
||||
bool r = decode(addr, addr_data);
|
||||
if (!r) return false;
|
||||
if (addr_data.size() <= addr_checksum_size) return false;
|
||||
|
||||
std::string checksum(addr_checksum_size, '\0');
|
||||
checksum = addr_data.substr(addr_data.size() - addr_checksum_size);
|
||||
|
||||
addr_data.resize(addr_data.size() - addr_checksum_size);
|
||||
crypto::hash hash = crypto::cn_fast_hash(addr_data.data(), addr_data.size());
|
||||
std::string expected_checksum(reinterpret_cast<const char*>(&hash), addr_checksum_size);
|
||||
if (expected_checksum != checksum) return false;
|
||||
|
||||
int read = tools::read_varint(addr_data.begin(), addr_data.end(), tag);
|
||||
if (read <= 0) return false;
|
||||
|
||||
data = addr_data.substr(read);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace base58
|
||||
{
|
||||
std::string encode(const std::string& data);
|
||||
bool decode(const std::string& enc, std::string& data);
|
||||
|
||||
std::string encode_addr(uint64_t tag, const std::string& data);
|
||||
bool decode_addr(std::string addr, uint64_t& tag, std::string& data);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <eos/portable_archive.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
#define CHECK_PROJECT_NAME() std::string project_name = CURRENCY_NAME; ar & project_name; if(!(project_name == CURRENCY_NAME) ) {throw std::runtime_error(std::string("wrong storage file: project name in file: ") + project_name + ", expected: " + CURRENCY_NAME );}
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
template<class t_object>
|
||||
bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
boost::filesystem::ofstream data_file;
|
||||
data_file.open( epee::string_encoding::utf8_to_wstring(file_path) , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
|
||||
boost::archive::binary_oarchive a(data_file);
|
||||
a << obj;
|
||||
|
||||
return !data_file.fail();
|
||||
CATCH_ENTRY_L0("serialize_obj_to_file: could not serialize into " << file_path, false);
|
||||
}
|
||||
|
||||
|
||||
template<class t_object>
|
||||
bool serialize_obj_to_buff(t_object& obj, std::string& buff)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::stringstream data_buff;
|
||||
|
||||
boost::archive::binary_oarchive a(data_buff);
|
||||
a << obj;
|
||||
buff = data_buff.str();
|
||||
return !data_buff.fail();
|
||||
CATCH_ENTRY_L0("serialize_obj_to_buff", false);
|
||||
}
|
||||
|
||||
template<class t_object, class t_stream>
|
||||
bool portble_serialize_obj_to_stream(t_object& obj, t_stream& stream)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
eos::portable_oarchive a(stream);
|
||||
a << obj;
|
||||
|
||||
return !stream.fail();
|
||||
CATCH_ENTRY_L0("portble_serialize_obj_to_stream", false);
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool unserialize_obj_from_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
boost::filesystem::ifstream data_file;
|
||||
data_file.open( epee::string_encoding::utf8_to_wstring(file_path), std::ios_base::binary | std::ios_base::in);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
boost::archive::binary_iarchive a(data_file);
|
||||
|
||||
a >> obj;
|
||||
return !data_file.fail();
|
||||
CATCH_ENTRY_L0("unserialize_obj_from_file: could not load " << file_path, false);
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool unserialize_obj_from_buff(t_object& obj, const std::string& buff)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
std::stringstream ss(buff);
|
||||
boost::archive::binary_iarchive a(ss);
|
||||
|
||||
a >> obj;
|
||||
return !ss.fail();
|
||||
CATCH_ENTRY_L0("unserialize_obj_from_buff", false);
|
||||
}
|
||||
|
||||
|
||||
template<class t_object, class t_stream>
|
||||
bool portable_unserialize_obj_from_stream(t_object& obj, t_stream& stream)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
eos::portable_iarchive a(stream);
|
||||
|
||||
a >> obj;
|
||||
return !stream.fail();
|
||||
CATCH_ENTRY_L0("portable_unserialize_obj_from_stream", false);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
#pragma comment(lib, "psapi.lib")
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
#pragma pack( push, before_imagehlp, 8 )
|
||||
#include <imagehlp.h>
|
||||
#pragma pack( pop, before_imagehlp )
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "callstack_helper.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct module_data
|
||||
{
|
||||
std::string image_name;
|
||||
std::string module_name;
|
||||
void *base_address;
|
||||
DWORD load_size;
|
||||
};
|
||||
|
||||
|
||||
class get_mod_info
|
||||
{
|
||||
HANDLE process;
|
||||
static const int buffer_length = 4096;
|
||||
public:
|
||||
get_mod_info(HANDLE h) : process(h) {}
|
||||
|
||||
module_data operator()(HMODULE module)
|
||||
{
|
||||
module_data ret;
|
||||
char temp[buffer_length];
|
||||
MODULEINFO mi;
|
||||
|
||||
GetModuleInformation(process, module, &mi, sizeof(mi));
|
||||
ret.base_address = mi.lpBaseOfDll;
|
||||
ret.load_size = mi.SizeOfImage;
|
||||
|
||||
GetModuleFileNameEx(process, module, temp, sizeof(temp));
|
||||
ret.image_name = temp;
|
||||
GetModuleBaseName(process, module, temp, sizeof(temp));
|
||||
ret.module_name = temp;
|
||||
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
|
||||
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
|
||||
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
std::string get_symbol_undecorated_name(HANDLE process, DWORD64 address, std::stringstream& ss)
|
||||
{
|
||||
SYMBOL_INFO* sym;
|
||||
static const int max_name_len = 1024;
|
||||
std::vector<char> sym_buffer(sizeof(SYMBOL_INFO) + max_name_len, '\0');
|
||||
sym = (SYMBOL_INFO *)sym_buffer.data();
|
||||
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
sym->MaxNameLen = max_name_len;
|
||||
|
||||
DWORD64 displacement;
|
||||
if (!SymFromAddr(process, address, &displacement, sym))
|
||||
return std::string("SymFromAddr failed1: ") + epee::string_tools::num_to_string_fast(GetLastError());
|
||||
|
||||
if (*sym->Name == '\0')
|
||||
return std::string("SymFromAddr failed2: ") + epee::string_tools::num_to_string_fast(GetLastError());
|
||||
|
||||
/*
|
||||
ss << " SizeOfStruct : " << sym->SizeOfStruct << ENDL;
|
||||
ss << " TypeIndex : " << sym->TypeIndex << ENDL; // Type Index of symbol
|
||||
ss << " Index : " << sym->Index << ENDL;
|
||||
ss << " Size : " << sym->Size << ENDL;
|
||||
ss << " ModBase : " << sym->ModBase << ENDL; // Base Address of module comtaining this symbol
|
||||
ss << " Flags : " << sym->Flags << ENDL;
|
||||
ss << " Value : " << sym->Value << ENDL; // Value of symbol, ValuePresent should be 1
|
||||
ss << " Address : " << sym->Address << ENDL; // Address of symbol including base address of module
|
||||
ss << " Register : " << sym->Register << ENDL; // register holding value or pointer to value
|
||||
ss << " Scope : " << sym->Scope << ENDL; // scope of the symbol
|
||||
ss << " Tag : " << sym->Tag << ENDL; // pdb classification
|
||||
ss << " NameLen : " << sym->NameLen << ENDL; // Actual length of name
|
||||
ss << " MaxNameLen : " << sym->MaxNameLen << ENDL;
|
||||
ss << " Name[1] : " << &sym->Name << ENDL; // Name of symbol
|
||||
*/
|
||||
|
||||
std::string und_name(max_name_len, '\0');
|
||||
DWORD chars_written = UnDecorateSymbolName(sym->Name, &und_name.front(), max_name_len, UNDNAME_COMPLETE);
|
||||
und_name.resize(chars_written);
|
||||
return und_name;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
std::string get_callstack_win_x64()
|
||||
{
|
||||
// @TODO@
|
||||
// static epee::static_helpers::wrapper<std::recursive_mutex> cs;
|
||||
static std::recursive_mutex cs;
|
||||
std::lock_guard<std::recursive_mutex> lock(cs);
|
||||
|
||||
HANDLE h_process = GetCurrentProcess();
|
||||
HANDLE h_thread = GetCurrentThread();
|
||||
|
||||
PCSTR user_search_path = NULL; // may be path to a pdb?
|
||||
if (!SymInitialize(h_process, user_search_path, false))
|
||||
return "<win callstack error 1>";
|
||||
|
||||
DWORD sym_options = SymGetOptions();
|
||||
sym_options |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME;
|
||||
SymSetOptions(sym_options);
|
||||
|
||||
DWORD cb_needed;
|
||||
std::vector<HMODULE> module_handles(1);
|
||||
EnumProcessModules(h_process, &module_handles[0], static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)), &cb_needed);
|
||||
module_handles.resize(cb_needed / sizeof(HMODULE));
|
||||
EnumProcessModules(h_process, &module_handles[0], static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)), &cb_needed);
|
||||
|
||||
std::vector<module_data> modules;
|
||||
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(h_process));
|
||||
void *base = modules[0].base_address;
|
||||
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof context);
|
||||
RtlCaptureContext( &context );
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof frame);
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rbp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
IMAGEHLP_LINE64 line = { 0 };
|
||||
line.SizeOfStruct = sizeof line;
|
||||
IMAGE_NT_HEADERS *image_nt_header = ImageNtHeader(base);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << ENDL;
|
||||
// ss << "main module loaded at 0x" << std::hex << std::setw(16) << std::setfill('0') << base << std::dec << " from " << modules[0].image_name << ENDL;
|
||||
for (size_t n = 0; n < 250; ++n)
|
||||
{
|
||||
if (!StackWalk64(image_nt_header->FileHeader.Machine, h_process, h_thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||||
break;
|
||||
if (frame.AddrReturn.Offset == 0)
|
||||
break;
|
||||
|
||||
std::string fnName = get_symbol_undecorated_name(h_process, frame.AddrPC.Offset, ss);
|
||||
ss << "0x" << std::setw(16) << std::setfill('0') << std::hex << frame.AddrPC.Offset << " " << std::dec << fnName;
|
||||
DWORD offset_from_line = 0;
|
||||
if (SymGetLineFromAddr64(h_process, frame.AddrPC.Offset, &offset_from_line, &line))
|
||||
ss << "+" << offset_from_line << " " << line.FileName << "(" << line.LineNumber << ")";
|
||||
|
||||
for (auto el : modules)
|
||||
{
|
||||
if ((DWORD64)el.base_address <= frame.AddrPC.Offset && frame.AddrPC.Offset < (DWORD64)el.base_address + (DWORD64)el.load_size)
|
||||
{
|
||||
ss << " : " << el.module_name << " @ 0x" << std::setw(0) << std::hex << (DWORD64)el.base_address << ENDL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
SymCleanup(h_process);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
||||
#endif // #if defined(WIN32)
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
#include <epee/include/misc_os_dependent.h>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
#if defined(WIN32)
|
||||
extern std::string get_callstack_win_x64();
|
||||
#endif
|
||||
|
||||
inline std::string get_callstack()
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
return epee::misc_utils::print_trace_default();
|
||||
#elif defined(WIN32)
|
||||
return get_callstack_win_x64();
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include "command_line.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
|
||||
namespace command_line
|
||||
{
|
||||
const arg_descriptor<bool> arg_help = {"help", "Produce help message"};
|
||||
const arg_descriptor<bool> arg_version = {"version", "Output version information"};
|
||||
const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory", ""};
|
||||
|
||||
const arg_descriptor<int> arg_stop_after_height = { "stop-after-height", "If specified, the daemon will stop immediately after a block with the given height is added", 0 };
|
||||
|
||||
const arg_descriptor<std::string> arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") };
|
||||
const arg_descriptor<bool> arg_os_version = { "os-version", "" };
|
||||
|
||||
const arg_descriptor<std::string> arg_log_dir = { "log-dir", "", "", true};
|
||||
const arg_descriptor<std::string> arg_log_file = { "log-file", "", "" };
|
||||
const arg_descriptor<int> arg_log_level = { "log-level", "", LOG_LEVEL_0, true };
|
||||
|
||||
const arg_descriptor<bool> arg_console = { "no-console", "Disable daemon console commands" };
|
||||
const arg_descriptor<bool> arg_show_details = { "currency-details", "Display currency details" };
|
||||
const arg_descriptor<bool> arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" };
|
||||
|
||||
const arg_descriptor<bool> arg_disable_upnp = { "disable-upnp", "Disable UPnP (enhances local network privacy)", false, true };
|
||||
|
||||
const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync = { "disable-stop-if-time-out-of-sync", "Do not stop the daemon if serious time synchronization problem is detected", false, true };
|
||||
const arg_descriptor<bool> arg_disable_stop_on_low_free_space = { "disable-stop-on-low-free-space", "Do not stop the daemon if free space at data dir is critically low", false, true };
|
||||
const arg_descriptor<bool> arg_enable_offers_service = { "enable-offers-service", "Enables marketplace feature", false, false};
|
||||
const arg_descriptor<std::string> arg_db_engine = { "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB, false };
|
||||
|
||||
const arg_descriptor<bool> arg_no_predownload = { "no-predownload", "Do not pre-download blockchain database", };
|
||||
const arg_descriptor<bool> arg_force_predownload = { "force-predownload", "Pre-download blockchain database regardless of it's status", };
|
||||
const arg_descriptor<bool> arg_validate_predownload = { "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database", };
|
||||
const arg_descriptor<std::string> arg_predownload_link = { "predownload-link", "Override url for blockchain database pre-downloading", "", true };
|
||||
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include "include_base_utils.h"
|
||||
|
||||
namespace command_line
|
||||
{
|
||||
template<typename T, bool required = false>
|
||||
struct arg_descriptor;
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<T, false>
|
||||
{
|
||||
typedef T value_type;
|
||||
arg_descriptor(const char* _name, const char* _description):
|
||||
name(_name),
|
||||
description(_description),
|
||||
not_use_default(true),
|
||||
default_value(T())
|
||||
{}
|
||||
arg_descriptor(const char* _name, const char* _description, const T& default_val) :
|
||||
name(_name),
|
||||
description(_description),
|
||||
not_use_default(false),
|
||||
default_value(default_val)
|
||||
{}
|
||||
arg_descriptor(const char* _name, const char* _description, const T& default_val, bool not_use_default) :
|
||||
name(_name),
|
||||
description(_description),
|
||||
default_value(default_val),
|
||||
not_use_default(not_use_default)
|
||||
{}
|
||||
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
T default_value;
|
||||
bool not_use_default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<std::vector<T>, false>
|
||||
{
|
||||
typedef std::vector<T> value_type;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<T, true>
|
||||
{
|
||||
static_assert(!std::is_same<T, bool>::value, "Boolean switch can't be required");
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/)
|
||||
{
|
||||
return boost::program_options::value<T>()->required();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
semantic->default_value(arg.default_value);
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
semantic->default_value(def);
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<std::vector<T>, char>* make_semantic(const arg_descriptor<std::vector<T>, false>& /*arg*/)
|
||||
{
|
||||
auto semantic = boost::program_options::value< std::vector<T> >();
|
||||
semantic->default_value(std::vector<T>(), "");
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T, bool required>
|
||||
void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required>& arg, bool unique = true)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, make_semantic(arg), arg.description);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, false>& arg, const T& def, bool unique = true)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, make_semantic(arg, def), arg.description);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void add_arg(boost::program_options::options_description& description, const arg_descriptor<bool, false>& arg, bool unique)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, boost::program_options::bool_switch(), arg.description);
|
||||
}
|
||||
|
||||
template<typename charT>
|
||||
boost::program_options::basic_parsed_options<charT> parse_command_line(int argc, const charT* const argv[],
|
||||
const boost::program_options::options_description& desc, bool allow_unregistered = false)
|
||||
{
|
||||
auto parser = boost::program_options::basic_command_line_parser<charT>(argc, argv);
|
||||
parser.options(desc);
|
||||
if (allow_unregistered)
|
||||
{
|
||||
parser.allow_unregistered();
|
||||
}
|
||||
return parser.run();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool handle_error_helper(const boost::program_options::options_description& desc, std::string& err, F parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
return parser();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
err = e.what();
|
||||
std::cerr << "Failed to parse arguments: " << e.what() << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Failed to parse arguments: unknown exception" << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool handle_error_helper(const boost::program_options::options_description& desc, F parser)
|
||||
{
|
||||
std::string stub_err;
|
||||
return handle_error_helper(desc, stub_err, parser);
|
||||
}
|
||||
|
||||
template<typename T, bool required>
|
||||
bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
|
||||
{
|
||||
auto value = vm[arg.name];
|
||||
return !value.empty();
|
||||
}
|
||||
|
||||
|
||||
template<typename T, bool required>
|
||||
T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
|
||||
{
|
||||
return vm[arg.name].template as<T>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool has_arg<bool, false>(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false>& arg)
|
||||
{
|
||||
return get_arg<bool, false>(vm, arg);
|
||||
}
|
||||
|
||||
#define ARG_DB_ENGINE_LMDB "lmdb"
|
||||
#define ARG_DB_ENGINE_MDBX "mdbx"
|
||||
|
||||
|
||||
extern const arg_descriptor<bool> arg_help;
|
||||
extern const arg_descriptor<bool> arg_version;
|
||||
extern const arg_descriptor<std::string> arg_data_dir;
|
||||
extern const arg_descriptor<int> arg_stop_after_height;
|
||||
extern const arg_descriptor<std::string> arg_config_file;
|
||||
extern const arg_descriptor<bool> arg_os_version;
|
||||
extern const arg_descriptor<std::string> arg_log_dir;
|
||||
extern const arg_descriptor<std::string> arg_log_file;
|
||||
extern const arg_descriptor<int> arg_log_level;
|
||||
extern const arg_descriptor<bool> arg_console;
|
||||
extern const arg_descriptor<bool> arg_show_details;
|
||||
extern const arg_descriptor<bool> arg_show_rpc_autodoc;
|
||||
extern const arg_descriptor<bool> arg_disable_upnp;
|
||||
extern const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync;
|
||||
extern const arg_descriptor<bool> arg_disable_stop_on_low_free_space;
|
||||
extern const arg_descriptor<bool> arg_enable_offers_service;
|
||||
extern const arg_descriptor<std::string> arg_db_engine;
|
||||
extern const arg_descriptor<bool> arg_no_predownload;
|
||||
extern const arg_descriptor<bool> arg_force_predownload;
|
||||
extern const arg_descriptor<bool> arg_validate_predownload;
|
||||
extern const arg_descriptor<std::string> arg_predownload_link;
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "wallet/view_iface.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct app_data_file_binary_header
|
||||
{
|
||||
uint64_t m_signature;
|
||||
uint64_t m_cb_body;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
inline
|
||||
std::string load_encrypted_file(const std::string& path, const std::string& key, std::string& body, uint64_t signature)
|
||||
{
|
||||
std::string app_data_buff;
|
||||
bool r = epee::file_io_utils::load_file_to_string(path, app_data_buff);
|
||||
if (!r)
|
||||
{
|
||||
return API_RETURN_CODE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (app_data_buff.size() < sizeof(app_data_file_binary_header))
|
||||
{
|
||||
LOG_ERROR("app_data_buff.size()(" << app_data_buff.size() << ") < sizeof(app_data_file_binary_header) (" << sizeof(app_data_file_binary_header) << ") check failed while loading from " << path);
|
||||
return API_RETURN_CODE_INVALID_FILE;
|
||||
}
|
||||
|
||||
crypto::chacha_crypt(app_data_buff, key);
|
||||
|
||||
const app_data_file_binary_header* phdr = reinterpret_cast<const app_data_file_binary_header*>(app_data_buff.data());
|
||||
if (phdr->m_signature != signature)
|
||||
{
|
||||
return API_RETURN_CODE_WRONG_PASSWORD;
|
||||
}
|
||||
body = app_data_buff.substr(sizeof(app_data_file_binary_header)).c_str();
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
inline
|
||||
std::string store_encrypted_file(const std::string& path, const std::string& key, const std::string& body, uint64_t signature)
|
||||
{
|
||||
std::string buff(sizeof(app_data_file_binary_header), 0);
|
||||
app_data_file_binary_header* phdr = (app_data_file_binary_header*)buff.data();
|
||||
phdr->m_signature = signature;
|
||||
phdr->m_cb_body = 0; // for future use
|
||||
|
||||
buff.append(body);
|
||||
crypto::chacha_crypt(buff, key);
|
||||
|
||||
bool r = epee::file_io_utils::save_string_to_file(path, buff);
|
||||
if (r)
|
||||
return API_RETURN_CODE_OK;
|
||||
else
|
||||
return API_RETURN_CODE_FAIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include "crypto_stream_operators.h"
|
||||
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash)
|
||||
{
|
||||
std::string buf;
|
||||
bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
|
||||
if (!res || buf.size() != sizeof(crypto::hash))
|
||||
{
|
||||
std::cout << "invalid hash format: <" << str_hash << '>' << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.copy(reinterpret_cast<char *>(&hash), sizeof(crypto::hash));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/RIPEMD160_helper.h"
|
||||
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
|
||||
|
||||
template <class T>
|
||||
std::ostream &print_t(std::ostream &o, const T &v)
|
||||
{
|
||||
return o << "" << epee::string_tools::pod_to_hex(v) << "";
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
std::ostream &print16(std::ostream &o, const T &v)
|
||||
{
|
||||
return o << "" << epee::string_tools::pod_to_hex(v).substr(0, 5) << "..";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string print16(const T &v)
|
||||
{
|
||||
return std::string("") + epee::string_tools::pod_to_hex(v).substr(0, 5) + "..";
|
||||
}
|
||||
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print_t(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash160 &v) { return print_t(o, v); }
|
||||
} // namespace crypto
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ENV32BIT
|
||||
#define CACHE_SIZE uint64_t(uint64_t(1UL * 128UL) * 1024UL * 1024UL * 1024UL)
|
||||
#else
|
||||
#define CACHE_SIZE (1 * 1024UL * 1024UL * 1024UL)
|
||||
#endif
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
typedef size_t container_handle;
|
||||
const uint64_t invalid_tx_id = 0;
|
||||
struct i_db_callback
|
||||
{
|
||||
virtual bool on_enum_item(uint64_t i, const void* pkey, uint64_t ks, const void* pval, uint64_t vs) = 0;
|
||||
};
|
||||
|
||||
struct stat_info
|
||||
{
|
||||
uint64_t tx_count;
|
||||
uint64_t write_tx_count;
|
||||
uint64_t map_size;
|
||||
};
|
||||
|
||||
struct i_db_backend
|
||||
{
|
||||
virtual bool close()=0;
|
||||
virtual bool begin_transaction(bool read_only = false) = 0;
|
||||
virtual bool commit_transaction()=0;
|
||||
virtual void abort_transaction()=0;
|
||||
virtual bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) = 0;
|
||||
virtual bool open_container(const std::string& name, container_handle& h)=0;
|
||||
virtual bool close_container(container_handle& h) = 0;
|
||||
virtual bool erase(container_handle h, const char* k, size_t s) = 0;
|
||||
virtual uint64_t size(container_handle h) = 0;
|
||||
virtual bool get(container_handle h, const char* k, size_t s, std::string& res_buff) = 0;
|
||||
virtual bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) = 0;
|
||||
virtual bool clear(container_handle h) = 0;
|
||||
virtual bool enumerate(container_handle h, i_db_callback* pcb)=0;
|
||||
virtual bool get_stat_info(stat_info& si) = 0;
|
||||
virtual const char* name()=0;
|
||||
virtual ~i_db_backend(){};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
|
||||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// #pragma once
|
||||
// #include "db_backend_leveldb.h"
|
||||
//
|
||||
// namespace tools
|
||||
// {
|
||||
// namespace db
|
||||
// {
|
||||
// level_db_backend : public i_db_backend
|
||||
// {
|
||||
// std::string m_path;
|
||||
// db_handle m_pdb;
|
||||
// public:
|
||||
// basic_db() :m_pdb(nullptr)
|
||||
// {}
|
||||
// ~basic_db(){ close(); }
|
||||
// bool close()
|
||||
// {
|
||||
// if (m_pdb)
|
||||
// delete m_pdb;
|
||||
// m_pdb = nullptr;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// void begin_transaction()
|
||||
// {
|
||||
// //leveldb is not supporting transactions yet
|
||||
// }
|
||||
//
|
||||
// void commit_transaction()
|
||||
// {
|
||||
// //leveldb is not supporting transactions yet
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool open(const std::string& path)
|
||||
// {
|
||||
// m_path = path;
|
||||
// close();
|
||||
// leveldb::Options options;
|
||||
// options.create_if_missing = true;
|
||||
// leveldb::Status status = leveldb::DB::Open(options, path, &m_pdb);
|
||||
// if (!status.ok())
|
||||
// {
|
||||
// LOG_ERROR("Unable to open/create database " << path << ", error: " << status.ToString());
|
||||
// return err_handle;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// bool erase(const char* k, size s)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::WriteOptions wo;
|
||||
// wo.sync = true;
|
||||
// leveldb::Status s = m_pdb->Delete(wo, leveldb::Slice(k, s));
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// CATCH_ENTRY_L0("get_t_object_from_db", false);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool get(const char* k, size s, std::string& res_buff)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::ReadOptions ro;
|
||||
// leveldb::Status s = m_pdb->Get(ro, leveldb::Slice(k, s), &res_buff);
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// CATCH_ENTRY_L0("get_t_object_from_db", false);
|
||||
// }
|
||||
//
|
||||
// bool clear()
|
||||
// {
|
||||
// close();
|
||||
// boost::system::error_code ec;
|
||||
// bool res = boost::filesystem::remove_all(m_path, ec);
|
||||
// if (!res)
|
||||
// {
|
||||
// LOG_ERROR("Failed to remove db file " << m_path << ", why: " << ec);
|
||||
// return false;
|
||||
// }
|
||||
// return open(m_path);
|
||||
// }
|
||||
//
|
||||
// bool set(const char* k, size s, const char* v, size vs)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::WriteOptions wo;
|
||||
// wo.sync = true;
|
||||
// leveldb::Status s = m_pdb->Put(wo, leveldb::Slice(k, s), leveldb::Slice(v, vs));
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// CATCH_ENTRY_L0("set_t_object_to_db", false);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "include_base_utils.h"
|
||||
|
||||
// #include "db_backend_base.h"
|
||||
//
|
||||
// #include "currency_db_base.h"
|
||||
// #include "leveldb/db.h"
|
||||
// #include "common/boost_serialization_helper.h"
|
||||
// #include "common/difficulty_boost_serialization.h"
|
||||
// #include "currency_format_utils.h"
|
||||
//
|
||||
//
|
||||
// namespace tools
|
||||
// {
|
||||
// namespace db
|
||||
// {
|
||||
// typedef leveldb::DB* db_handle;
|
||||
//
|
||||
// static const db_handle err_handle = nullptr;
|
||||
//
|
||||
// class level_db_backend : public i_db_backend
|
||||
// {
|
||||
// std::string m_path;
|
||||
// db_handle m_pdb;
|
||||
// public:
|
||||
// level_db_backend() :m_pdb(nullptr)
|
||||
// {}
|
||||
// ~level_db_backend(){ close(); }
|
||||
// bool close();
|
||||
// void begin_transaction();
|
||||
// void commit_transaction();
|
||||
// bool open(const std::string& path);
|
||||
// bool erase(const char* k, size s);
|
||||
// bool get(const char* k, size s, std::string& res_buff);
|
||||
// bool clear();
|
||||
// bool set(const char* k, size s, const char* v, size vs);
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
|
@ -1,401 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "db_backend_lmdb.h"
|
||||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
#include "profile_tools.h"
|
||||
#include "util.h"
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
|
||||
#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(rc == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_THROW_MESS_LMDB_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(rc == MDB_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define ASSERT_MES_AND_THROW_LMDB(rc, mess) ASSERT_MES_AND_THROW("[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "lmdb"
|
||||
// 'lmdb' channel is disabled by default
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
lmdb_db_backend::lmdb_db_backend() : m_penv(AUTO_VAL_INIT(m_penv))
|
||||
{
|
||||
|
||||
}
|
||||
lmdb_db_backend::~lmdb_db_backend()
|
||||
{
|
||||
NESTED_TRY_ENTRY();
|
||||
|
||||
close();
|
||||
|
||||
NESTED_CATCH_ENTRY(__func__);
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::open(const std::string& path_, uint64_t cache_sz)
|
||||
{
|
||||
int res = 0;
|
||||
res = mdb_env_create(&m_penv);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_create");
|
||||
|
||||
res = mdb_env_set_maxdbs(m_penv, 15);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_maxdbs");
|
||||
|
||||
res = mdb_env_set_mapsize(m_penv, cache_sz);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize");
|
||||
|
||||
m_path = path_;
|
||||
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_path), false, "create_directories_if_necessary failed: " << m_path);
|
||||
|
||||
res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD , 0644);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_open, m_path=" << m_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::open_container(const std::string& name, container_handle& h)
|
||||
{
|
||||
MDB_dbi dbi = AUTO_VAL_INIT(dbi);
|
||||
begin_transaction();
|
||||
int res = mdb_dbi_open(get_current_tx(), name.c_str(), MDB_CREATE, &dbi);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_dbi_open with container name: " << name);
|
||||
commit_transaction();
|
||||
h = static_cast<container_handle>(dbi);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::close_container(container_handle& h)
|
||||
{
|
||||
static const container_handle null_handle = AUTO_VAL_INIT(null_handle);
|
||||
CHECK_AND_ASSERT_MES(h != null_handle, false, "close_container is called for null container handle");
|
||||
MDB_dbi dbi = static_cast<MDB_dbi>(h);
|
||||
begin_transaction();
|
||||
mdb_dbi_close(m_penv, dbi);
|
||||
commit_transaction();
|
||||
h = null_handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::close()
|
||||
{
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& tx_thread : m_txs)
|
||||
{
|
||||
for (auto txe : tx_thread.second)
|
||||
{
|
||||
int res = mdb_txn_commit(txe.ptx);
|
||||
if (res != MDB_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("[DB ERROR]: On close tranactions: " << mdb_strerror(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_txs.clear();
|
||||
}
|
||||
if (m_penv)
|
||||
{
|
||||
mdb_env_close(m_penv);
|
||||
m_penv = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::begin_transaction(bool read_only)
|
||||
{
|
||||
if (!read_only)
|
||||
{
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3);
|
||||
CRITICAL_SECTION_LOCK(m_write_exclusive_lock);
|
||||
}
|
||||
PROFILE_FUNC("lmdb_db_backend::begin_transaction");
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
transactions_list& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
MDB_txn* pparent_tx = nullptr;
|
||||
MDB_txn* p_new_tx = nullptr;
|
||||
bool parent_read_only = false;
|
||||
if (rtxlist.size())
|
||||
{
|
||||
pparent_tx = rtxlist.back().ptx;
|
||||
parent_read_only = rtxlist.back().read_only;
|
||||
}
|
||||
|
||||
|
||||
if (pparent_tx && read_only)
|
||||
{
|
||||
++rtxlist.back().count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int res = 0;
|
||||
unsigned int flags = 0;
|
||||
if (read_only)
|
||||
flags += MDB_RDONLY;
|
||||
|
||||
//don't use parent tx in write transactions if parent tx was read-only (restriction in lmdb)
|
||||
//see "Nested transactions: Max 1 child, write txns only, no writemap"
|
||||
if (pparent_tx && parent_read_only)
|
||||
pparent_tx = nullptr;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
res = mdb_txn_begin(m_penv, pparent_tx, flags, &p_new_tx);
|
||||
if(res != MDB_SUCCESS)
|
||||
{
|
||||
//Important: if mdb_txn_begin is failed need to unlock previously locked mutex
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
//throw exception to avoid regular code execution
|
||||
ASSERT_MES_AND_THROW_LMDB(res, "Unable to mdb_txn_begin");
|
||||
}
|
||||
|
||||
rtxlist.push_back(tx_entry());
|
||||
rtxlist.back().count = read_only ? 1 : 0;
|
||||
rtxlist.back().ptx = p_new_tx;
|
||||
rtxlist.back().read_only = read_only;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOG_PRINT_L4("[DB] Transaction started");
|
||||
return true;
|
||||
}
|
||||
|
||||
MDB_txn* lmdb_db_backend::get_current_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
CHECK_AND_ASSERT_MES(rtxlist.size(), nullptr, "Unable to find active tx for thread " << std::this_thread::get_id());
|
||||
return rtxlist.back().ptx;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::pop_tx_entry(tx_entry& txe)
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
CHECK_AND_ASSERT_MES(it != m_txs.end(), false, "[DB] Unable to find id cor current thread");
|
||||
CHECK_AND_ASSERT_MES(it->second.size(), false, "[DB] No active tx for current thread");
|
||||
|
||||
txe = it->second.back();
|
||||
|
||||
if (it->second.back().read_only && it->second.back().count == 0)
|
||||
{
|
||||
LOG_ERROR("Internal db tx state error: read_only and count readers == 0");
|
||||
}
|
||||
|
||||
if ((it->second.back().read_only && it->second.back().count < 2) || (!it->second.back().read_only && it->second.back().count < 1))
|
||||
{
|
||||
it->second.pop_back();
|
||||
if (!it->second.size())
|
||||
m_txs.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--it->second.back().count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::commit_transaction()
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::commit_transaction");
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Unable to pop_tx_entry");
|
||||
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
int res = 0;
|
||||
res = mdb_txn_commit(txe.ptx);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_txn_commit (error " << res << ")");
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction committed");
|
||||
return true;
|
||||
}
|
||||
|
||||
void lmdb_db_backend::abort_transaction()
|
||||
{
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, void(), "Unable to pop_tx_entry");
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
mdb_txn_abort(txe.ptx);
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction aborted");
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::erase(container_handle h, const char* k, size_t ks)
|
||||
{
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
|
||||
res = mdb_del(get_current_tx(), static_cast<MDB_dbi>(h), &key, nullptr);
|
||||
if (res == MDB_NOTFOUND)
|
||||
return false;
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_del");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::have_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
if (it == m_txs.end())
|
||||
return false;
|
||||
return it->second.size() ? true : false;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::get(container_handle h, const char* k, size_t ks, std::string& res_buff)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::get");
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data = AUTO_VAL_INIT(data);
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
|
||||
res = mdb_get(get_current_tx(), static_cast<MDB_dbi>(h), &key, &data);
|
||||
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
|
||||
if (res == MDB_NOTFOUND)
|
||||
return false;
|
||||
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_get, h: " << h << ", ks: " << ks);
|
||||
res_buff.assign((const char*)data.mv_data, data.mv_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::clear(container_handle h)
|
||||
{
|
||||
int res = mdb_drop(get_current_tx(), static_cast<MDB_dbi>(h), 0);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_drop");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t lmdb_db_backend::size(container_handle h)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::size");
|
||||
MDB_stat container_stat = AUTO_VAL_INIT(container_stat);
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
int res = mdb_stat(get_current_tx(), static_cast<MDB_dbi>(h), &container_stat);
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_stat");
|
||||
return container_stat.ms_entries;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::set(container_handle h, const char* k, size_t ks, const char* v, size_t vs)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::set");
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data[2] = {}; // mdb_put may access data[1] if some flags are set, this may trigger static code analizers, so here we allocate two elements to avoid it
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
data[0].mv_data = (void*)v;
|
||||
data[0].mv_size = vs;
|
||||
|
||||
res = mdb_put(get_current_tx(), static_cast<MDB_dbi>(h), &key, data, 0);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_put");
|
||||
return true;
|
||||
}
|
||||
bool lmdb_db_backend::enumerate(container_handle h, i_db_callback* pcb)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate");
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data = AUTO_VAL_INIT(data);
|
||||
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
MDB_cursor* cursor_ptr = nullptr;
|
||||
int res = mdb_cursor_open(get_current_tx(), static_cast<MDB_dbi>(h), &cursor_ptr);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_cursor_open");
|
||||
CHECK_AND_ASSERT_MES(cursor_ptr, false, "cursor_ptr is null after mdb_cursor_open");
|
||||
|
||||
uint64_t count = 0;
|
||||
do
|
||||
{
|
||||
int res = mdb_cursor_get(cursor_ptr, &key, &data, MDB_NEXT);
|
||||
if (res == MDB_NOTFOUND)
|
||||
break;
|
||||
if (!pcb->on_enum_item(count, key.mv_data, key.mv_size, data.mv_data, data.mv_size))
|
||||
break;
|
||||
count++;
|
||||
} while (cursor_ptr);
|
||||
|
||||
mdb_cursor_close(cursor_ptr);
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::get_stat_info(tools::db::stat_info& si)
|
||||
{
|
||||
si = AUTO_VAL_INIT_T(tools::db::stat_info);
|
||||
|
||||
MDB_envinfo ei = AUTO_VAL_INIT(ei);
|
||||
mdb_env_info(m_penv, &ei);
|
||||
si.map_size = ei.me_mapsize;
|
||||
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& e : m_txs)
|
||||
{
|
||||
for (auto& pr : e.second)
|
||||
{
|
||||
++si.tx_count;
|
||||
if(!pr.read_only)
|
||||
++si.write_tx_count;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const char* lmdb_db_backend::name()
|
||||
{
|
||||
return "lmdb";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL NULL
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "db_backend_base.h"
|
||||
#include "db/liblmdb/lmdb.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
class lmdb_db_backend : public i_db_backend
|
||||
{
|
||||
|
||||
struct tx_entry
|
||||
{
|
||||
MDB_txn* ptx;
|
||||
bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access
|
||||
size_t count; //count of read-only nested emulated transactions
|
||||
};
|
||||
typedef std::list<tx_entry> transactions_list;
|
||||
|
||||
|
||||
std::string m_path;
|
||||
MDB_env *m_penv;
|
||||
|
||||
boost::recursive_mutex m_cs;
|
||||
boost::recursive_mutex m_write_exclusive_lock;
|
||||
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
|
||||
bool pop_tx_entry(tx_entry& txe);
|
||||
public:
|
||||
lmdb_db_backend();
|
||||
~lmdb_db_backend();
|
||||
|
||||
//----------------- i_db_backend -----------------------------------------------------
|
||||
bool close() override;
|
||||
bool begin_transaction(bool read_only = false) override;
|
||||
bool commit_transaction() override;
|
||||
void abort_transaction() override;
|
||||
bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) override;
|
||||
bool open_container(const std::string& name, container_handle& h) override;
|
||||
bool close_container(container_handle& h) override;
|
||||
bool erase(container_handle h, const char* k, size_t s) override;
|
||||
bool get(container_handle h, const char* k, size_t s, std::string& res_buff) override;
|
||||
bool clear(container_handle h) override;
|
||||
uint64_t size(container_handle h) override;
|
||||
bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) override;
|
||||
bool enumerate(container_handle h, i_db_callback* pcb) override;
|
||||
bool get_stat_info(tools::db::stat_info& si) override;
|
||||
const char* name() override;
|
||||
//-------------------------------------------------------------------------------------
|
||||
bool have_tx();
|
||||
MDB_txn* get_current_tx();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,413 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifdef ENABLED_ENGINE_MDBX
|
||||
#include "db_backend_mdbx.h"
|
||||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
#include "profile_tools.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
|
||||
#define CHECK_AND_ASSERT_MESS_MDBX_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDBX_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_THROW_MESS_MDBX_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(res == MDBX_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
|
||||
#define ASSERT_MES_AND_THROW_MDBX(rc, mess) ASSERT_MES_AND_THROW("[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "mdbx"
|
||||
// 'mdbx' channel is disabled by default
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
mdbx_db_backend::mdbx_db_backend() : m_penv(AUTO_VAL_INIT(m_penv))
|
||||
{
|
||||
|
||||
}
|
||||
mdbx_db_backend::~mdbx_db_backend()
|
||||
{
|
||||
NESTED_TRY_ENTRY();
|
||||
|
||||
close();
|
||||
|
||||
NESTED_CATCH_ENTRY(__func__);
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::open(const std::string& path_, uint64_t cache_sz)
|
||||
{
|
||||
int res = 0;
|
||||
res = mdbx_env_create(&m_penv);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_create");
|
||||
|
||||
res = mdbx_env_set_maxdbs(m_penv, 15);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_set_maxdbs");
|
||||
|
||||
intptr_t size_lower = 0;
|
||||
intptr_t size_now = -1; //don't change current database size
|
||||
intptr_t size_upper = 0x10000000000; //don't set db file size limit
|
||||
intptr_t growth_step = 0x40000000; //increment step 1GB
|
||||
intptr_t shrink_threshold = -1;
|
||||
intptr_t pagesize = 0x00001000; //4kb
|
||||
res = mdbx_env_set_geometry(m_penv, size_lower, size_now, size_upper, growth_step, shrink_threshold, pagesize);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_set_mapsize");
|
||||
|
||||
m_path = path_;
|
||||
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_path), false, "create_directories_if_necessary failed: " << m_path);
|
||||
|
||||
res = mdbx_env_open(m_penv, m_path.c_str(), MDBX_NORDAHEAD , 0644);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_open, m_path=" << m_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::open_container(const std::string& name, container_handle& h)
|
||||
{
|
||||
MDBX_dbi dbi = AUTO_VAL_INIT(dbi);
|
||||
begin_transaction();
|
||||
int res = mdbx_dbi_open(get_current_tx(), name.c_str(), MDBX_CREATE, &dbi);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_dbi_open with container name: " << name);
|
||||
commit_transaction();
|
||||
h = static_cast<container_handle>(dbi);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::close_container(container_handle& h)
|
||||
{
|
||||
static const container_handle null_handle = AUTO_VAL_INIT(null_handle);
|
||||
CHECK_AND_ASSERT_MES(h != null_handle, false, "close_container is called for null container handle");
|
||||
|
||||
MDBX_dbi dbi = static_cast<MDBX_dbi>(h);
|
||||
begin_transaction();
|
||||
mdbx_dbi_close(m_penv, dbi);
|
||||
commit_transaction();
|
||||
h = null_handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::close()
|
||||
{
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& tx_thread : m_txs)
|
||||
{
|
||||
for (auto txe : tx_thread.second)
|
||||
{
|
||||
int res = mdbx_txn_commit(txe.ptx);
|
||||
if (res != MDBX_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("[DB ERROR]: On close tranactions: " << mdbx_strerror(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_txs.clear();
|
||||
}
|
||||
if (m_penv)
|
||||
{
|
||||
mdbx_env_close(m_penv);
|
||||
m_penv = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::begin_transaction(bool read_only)
|
||||
{
|
||||
if (!read_only)
|
||||
{
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3);
|
||||
CRITICAL_SECTION_LOCK(m_write_exclusive_lock);
|
||||
}
|
||||
PROFILE_FUNC("mdbx_db_backend::begin_transaction");
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
transactions_list& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
MDBX_txn* pparent_tx = nullptr;
|
||||
MDBX_txn* p_new_tx = nullptr;
|
||||
bool parent_read_only = false;
|
||||
if (rtxlist.size())
|
||||
{
|
||||
pparent_tx = rtxlist.back().ptx;
|
||||
parent_read_only = rtxlist.back().read_only;
|
||||
}
|
||||
|
||||
|
||||
if (pparent_tx && read_only)
|
||||
{
|
||||
++rtxlist.back().count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int res = 0;
|
||||
//MDBX_txn_flags_t flags = MDBX_txn_flags_t();
|
||||
unsigned int flags = 0;
|
||||
if (read_only)
|
||||
flags = MDBX_RDONLY;//flags = MDBX_TXN_RDONLY;
|
||||
|
||||
//don't use parent tx in write transactions if parent tx was read-only (restriction in mdbx)
|
||||
//see "Nested transactions: Max 1 child, write txns only, no writemap"
|
||||
if (pparent_tx && parent_read_only)
|
||||
pparent_tx = nullptr;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
res = mdbx_txn_begin(m_penv, pparent_tx, flags, &p_new_tx);
|
||||
if(res != MDBX_SUCCESS)
|
||||
{
|
||||
//Important: if mdbx_txn_begin is failed need to unlock previously locked mutex
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
//throw exception to avoid regular code execution
|
||||
ASSERT_MES_AND_THROW_MDBX(res, "Unable to mdbx_txn_begin");
|
||||
}
|
||||
|
||||
rtxlist.push_back(tx_entry());
|
||||
rtxlist.back().count = read_only ? 1 : 0;
|
||||
rtxlist.back().ptx = p_new_tx;
|
||||
rtxlist.back().read_only = read_only;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOG_PRINT_L4("[DB] Transaction started");
|
||||
return true;
|
||||
}
|
||||
|
||||
MDBX_txn* mdbx_db_backend::get_current_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
CHECK_AND_ASSERT_MES(rtxlist.size(), nullptr, "Unable to find active tx for thread " << std::this_thread::get_id());
|
||||
return rtxlist.back().ptx;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::pop_tx_entry(tx_entry& txe)
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
CHECK_AND_ASSERT_MES(it != m_txs.end(), false, "[DB] Unable to find id cor current thread");
|
||||
CHECK_AND_ASSERT_MES(it->second.size(), false, "[DB] No active tx for current thread");
|
||||
|
||||
txe = it->second.back();
|
||||
|
||||
if (it->second.back().read_only && it->second.back().count == 0)
|
||||
{
|
||||
LOG_ERROR("Internal db tx state error: read_only and count readers == 0");
|
||||
}
|
||||
|
||||
if ((it->second.back().read_only && it->second.back().count < 2) || (!it->second.back().read_only && it->second.back().count < 1))
|
||||
{
|
||||
it->second.pop_back();
|
||||
if (!it->second.size())
|
||||
m_txs.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--it->second.back().count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::commit_transaction()
|
||||
{
|
||||
PROFILE_FUNC("mdbx_db_backend::commit_transaction");
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Unable to pop_tx_entry");
|
||||
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
int res = 0;
|
||||
res = mdbx_txn_commit(txe.ptx);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_txn_commit (error " << res << ")");
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction committed");
|
||||
return true;
|
||||
}
|
||||
|
||||
void mdbx_db_backend::abort_transaction()
|
||||
{
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, void(), "Unable to pop_tx_entry");
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
mdbx_txn_abort(txe.ptx);
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction aborted");
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::erase(container_handle h, const char* k, size_t ks)
|
||||
{
|
||||
int res = 0;
|
||||
MDBX_val key = AUTO_VAL_INIT(key);
|
||||
key.iov_base = (void*)k;
|
||||
key.iov_len = ks;
|
||||
|
||||
res = mdbx_del(get_current_tx(), static_cast<MDBX_dbi>(h), &key, nullptr);
|
||||
if (res == MDBX_NOTFOUND)
|
||||
return false;
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_del");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::have_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
if (it == m_txs.end())
|
||||
return false;
|
||||
return it->second.size() ? true : false;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::get(container_handle h, const char* k, size_t ks, std::string& res_buff)
|
||||
{
|
||||
PROFILE_FUNC("mdbx_db_backend::get");
|
||||
int res = 0;
|
||||
MDBX_val key = AUTO_VAL_INIT(key);
|
||||
MDBX_val data = AUTO_VAL_INIT(data);
|
||||
key.iov_base = (void*)k;
|
||||
key.iov_len = ks;
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
|
||||
res = mdbx_get(get_current_tx(), static_cast<MDBX_dbi>(h), &key, &data);
|
||||
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
|
||||
if (res == MDBX_NOTFOUND)
|
||||
return false;
|
||||
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_get, h: " << h << ", ks: " << ks);
|
||||
res_buff.assign((const char*)data.iov_base, data.iov_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::clear(container_handle h)
|
||||
{
|
||||
int res = mdbx_drop(get_current_tx(), static_cast<MDBX_dbi>(h), 0);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_drop");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t mdbx_db_backend::size(container_handle h)
|
||||
{
|
||||
PROFILE_FUNC("mdbx_db_backend::size");
|
||||
MDBX_stat container_stat = AUTO_VAL_INIT(container_stat);
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
int res = mdbx_dbi_stat(get_current_tx(), static_cast<MDBX_dbi>(h), &container_stat, sizeof(MDBX_stat));
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_stat");
|
||||
return container_stat.ms_entries;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::set(container_handle h, const char* k, size_t ks, const char* v, size_t vs)
|
||||
{
|
||||
PROFILE_FUNC("mdbx_db_backend::set");
|
||||
int res = 0;
|
||||
MDBX_val key = AUTO_VAL_INIT(key);
|
||||
MDBX_val data[2] = {}; // mdbx_put may access data[1] if some flags are set, this may trigger static code analizers, so here we allocate two elements to avoid it
|
||||
key.iov_base = (void*)k;
|
||||
key.iov_len = ks;
|
||||
data[0].iov_base = (void*)v;
|
||||
data[0].iov_len = vs;
|
||||
|
||||
//MDBX_put_flags_t flags = MDBX_put_flags_t();
|
||||
unsigned flags = 0;
|
||||
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, data, flags);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_put");
|
||||
return true;
|
||||
}
|
||||
bool mdbx_db_backend::enumerate(container_handle h, i_db_callback* pcb)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate");
|
||||
MDBX_val key = AUTO_VAL_INIT(key);
|
||||
MDBX_val data = AUTO_VAL_INIT(data);
|
||||
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
MDBX_cursor* cursor_ptr = nullptr;
|
||||
int res = mdbx_cursor_open(get_current_tx(), static_cast<MDBX_dbi>(h), &cursor_ptr);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_cursor_open");
|
||||
CHECK_AND_ASSERT_MES(cursor_ptr, false, "cursor_ptr is null after mdbx_cursor_open");
|
||||
|
||||
uint64_t count = 0;
|
||||
do
|
||||
{
|
||||
int res = mdbx_cursor_get(cursor_ptr, &key, &data, MDBX_NEXT);
|
||||
if (res == MDBX_NOTFOUND)
|
||||
break;
|
||||
if (!pcb->on_enum_item(count, key.iov_base, key.iov_len, data.iov_base, data.iov_len))
|
||||
break;
|
||||
count++;
|
||||
} while (cursor_ptr);
|
||||
|
||||
mdbx_cursor_close(cursor_ptr);
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mdbx_db_backend::get_stat_info(tools::db::stat_info& si)
|
||||
{
|
||||
si = AUTO_VAL_INIT_T(tools::db::stat_info);
|
||||
|
||||
MDBX_envinfo ei = AUTO_VAL_INIT(ei);
|
||||
mdbx_env_info(m_penv, &ei, sizeof(MDBX_envinfo));
|
||||
si.map_size = ei.mi_mapsize;
|
||||
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& e : m_txs)
|
||||
{
|
||||
for (auto& pr : e.second)
|
||||
{
|
||||
++si.tx_count;
|
||||
if(!pr.read_only)
|
||||
++si.write_tx_count;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const char* mdbx_db_backend::name()
|
||||
{
|
||||
return "mdbx";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL NULL
|
||||
#endif
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#ifdef ENABLED_ENGINE_MDBX
|
||||
#include <thread>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "db_backend_base.h"
|
||||
#include "db/libmdbx/mdbx.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
class mdbx_db_backend : public i_db_backend
|
||||
{
|
||||
|
||||
struct tx_entry
|
||||
{
|
||||
MDBX_txn* ptx;
|
||||
bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access
|
||||
size_t count; //count of read-only nested emulated transactions
|
||||
};
|
||||
typedef std::list<tx_entry> transactions_list;
|
||||
|
||||
|
||||
std::string m_path;
|
||||
MDBX_env *m_penv;
|
||||
|
||||
boost::recursive_mutex m_cs;
|
||||
boost::recursive_mutex m_write_exclusive_lock;
|
||||
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
|
||||
bool pop_tx_entry(tx_entry& txe);
|
||||
public:
|
||||
mdbx_db_backend();
|
||||
~mdbx_db_backend();
|
||||
|
||||
//----------------- i_db_backend -----------------------------------------------------
|
||||
bool close() override;
|
||||
bool begin_transaction(bool read_only = false) override;
|
||||
bool commit_transaction() override;
|
||||
void abort_transaction() override;
|
||||
bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) override;
|
||||
bool open_container(const std::string& name, container_handle& h) override;
|
||||
bool close_container(container_handle& h) override;
|
||||
bool erase(container_handle h, const char* k, size_t s) override;
|
||||
bool get(container_handle h, const char* k, size_t s, std::string& res_buff) override;
|
||||
bool clear(container_handle h) override;
|
||||
uint64_t size(container_handle h) override;
|
||||
bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) override;
|
||||
bool enumerate(container_handle h, i_db_callback* pcb) override;
|
||||
bool get_stat_info(tools::db::stat_info& si) override;
|
||||
const char* name() override;
|
||||
//-------------------------------------------------------------------------------------
|
||||
bool have_tx();
|
||||
MDBX_txn* get_current_tx();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "db_backend_selector.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include "command_line.h"
|
||||
#include "db_backend_lmdb.h"
|
||||
#include "db_backend_mdbx.h"
|
||||
|
||||
#define LMDB_MAIN_FILE_NAME "data.mdb"
|
||||
#define MDBX_MAIN_FILE_NAME "mdbx.dat"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
|
||||
db_backend_selector::db_backend_selector()
|
||||
: m_engine_type(db_none)
|
||||
{
|
||||
}
|
||||
|
||||
void db_backend_selector::init_options(boost::program_options::options_description& desc)
|
||||
{
|
||||
command_line::add_arg(desc, command_line::arg_db_engine);
|
||||
}
|
||||
|
||||
bool db_backend_selector::init(const boost::program_options::variables_map& vm)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_LMDB)
|
||||
{
|
||||
m_engine_type = db_lmdb;
|
||||
}
|
||||
else if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_MDBX)
|
||||
{
|
||||
#ifdef ENABLED_ENGINE_MDBX
|
||||
m_engine_type = db_mdbx;
|
||||
#else
|
||||
LOG_PRINT_L0(" DB ENGINE: " << ARG_DB_ENGINE_MDBX << " is not suported by this build(see DISABLE_MDBX cmake option), STOPPING");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED_L0("UNKNOWN DB ENGINE: " << command_line::get_arg(vm, command_line::arg_db_engine) << ", STOPPING");
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG_ERROR("internal error: db_backend_selector::init failed on command-line parsing, exception: " << e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_engine_type == db_none)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_db_folder_path() const
|
||||
{
|
||||
//CHECK_AND_ASSERT_THROW_MES(m_engine_type != db_none, "db_backend_selector was no inited");
|
||||
return m_config_folder + ("/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX) + get_engine_name() + CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX;
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_temp_db_folder_path() const
|
||||
{
|
||||
//CHECK_AND_ASSERT_THROW_MES(m_engine_type != db_none, "db_backend_selector was no inited");
|
||||
return get_temp_config_folder() + ("/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX) + get_engine_name() + CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX;
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_pool_db_folder_path() const
|
||||
{
|
||||
return m_config_folder + ("/" CURRENCY_POOLDATA_FOLDERNAME_PREFIX) + get_engine_name() + CURRENCY_POOLDATA_FOLDERNAME_SUFFIX;
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_db_main_file_name() const
|
||||
{
|
||||
switch (m_engine_type)
|
||||
{
|
||||
case db_lmdb:
|
||||
return LMDB_MAIN_FILE_NAME;
|
||||
case db_mdbx:
|
||||
return MDBX_MAIN_FILE_NAME;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_engine_name() const
|
||||
{
|
||||
switch (m_engine_type)
|
||||
{
|
||||
case db_lmdb:
|
||||
return "lmdb";
|
||||
case db_mdbx:
|
||||
return "mdbx";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<tools::db::i_db_backend> db_backend_selector::create_backend()
|
||||
{
|
||||
switch (m_engine_type)
|
||||
{
|
||||
case db_lmdb:
|
||||
return std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend);
|
||||
|
||||
case db_mdbx:
|
||||
return std::shared_ptr<tools::db::i_db_backend>(new tools::db::mdbx_db_backend);
|
||||
|
||||
default:
|
||||
LOG_ERROR("db_backend_selector was no inited");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_backend_selector::get_temp_config_folder() const
|
||||
{
|
||||
return m_config_folder + "_TEMP";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace db
|
||||
} // namespace tools
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include "misc_language.h"
|
||||
#include "db_backend_base.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
enum db_engine_type { db_none = 0, db_lmdb, db_mdbx };
|
||||
|
||||
class db_backend_selector
|
||||
{
|
||||
public:
|
||||
db_backend_selector();
|
||||
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
|
||||
std::string get_db_folder_path() const;
|
||||
std::string get_db_main_file_name() const;
|
||||
db_engine_type get_engine_type() const { return m_engine_type; }
|
||||
std::string get_engine_name() const;
|
||||
std::string get_config_folder() const { return m_config_folder; }
|
||||
std::string get_temp_config_folder() const;
|
||||
std::string get_temp_db_folder_path() const;
|
||||
|
||||
std::string get_pool_db_folder_path() const;
|
||||
|
||||
std::shared_ptr<tools::db::i_db_backend> create_backend();
|
||||
|
||||
private:
|
||||
db_engine_type m_engine_type;
|
||||
std::string m_config_folder;
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
} // namespace tools
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//---------------------------------------------------
|
||||
template <class archive_t>
|
||||
inline void serialize(archive_t &a, currency::wide_difficulty_type &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
if(archive_t::is_loading::value)
|
||||
{
|
||||
//load high part
|
||||
uint64_t v = 0;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "loading" << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
x = v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "hight part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
//load low part
|
||||
x = x << 64;
|
||||
a & v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "low part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
x += v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "loaded value: " << std::hex << x << ENDL;
|
||||
#endif
|
||||
}else
|
||||
{
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "storing" << ENDL;
|
||||
#endif
|
||||
//store high part
|
||||
currency::wide_difficulty_type x_ = x;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "original: " << std::hex << x_ << ENDL;
|
||||
#endif
|
||||
x_ = x_ >> 64;
|
||||
uint64_t v = x_.convert_to<uint64_t>();
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "hight part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
//store low part
|
||||
x_ = x;
|
||||
x_ = x_ << 64;
|
||||
x_ = x_ >> 64;
|
||||
v = x_.convert_to<uint64_t>();
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "low part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include "encryption_filter.h"
|
||||
#include "crypto/chacha8_stream.h"
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <iosfwd>
|
||||
#include <type_traits>
|
||||
#include <boost/iostreams/categories.hpp> // sink_tag
|
||||
#include <boost/iostreams/operations.hpp> // boost::iostreams::write, boost::iostreams::read
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/chacha8.h"
|
||||
#include "crypto/chacha8_stream.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
class encrypt_chacha_processer_base
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
//typedef boost::iostreams::multichar_output_filter_tag category;
|
||||
//typedef boost::iostreams::flushable_tag category;
|
||||
static const uint32_t block_size = ECRYPT_BLOCKLENGTH;
|
||||
|
||||
encrypt_chacha_processer_base(std::string const &pass, const crypto::chacha8_iv& iv) :m_iv(iv), m_ctx(AUTO_VAL_INIT(m_ctx))
|
||||
{
|
||||
crypto::generate_chacha8_key(pass, m_key);
|
||||
ECRYPT_keysetup(&m_ctx, &m_key.data[0], sizeof(m_key.data) * 8, sizeof(m_iv.data) * 8);
|
||||
ECRYPT_ivsetup(&m_ctx, &m_iv.data[0]);
|
||||
}
|
||||
~encrypt_chacha_processer_base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename cb_handler>
|
||||
std::streamsize process(char_type const * const buf, std::streamsize const n, cb_handler cb) const
|
||||
{
|
||||
if (n == 0)
|
||||
return n;
|
||||
if (n%ECRYPT_BLOCKLENGTH == 0 && m_buff.empty())
|
||||
{
|
||||
std::vector<char_type> buff(n);
|
||||
ECRYPT_encrypt_blocks(&m_ctx, (u8*)buf, (u8*)&buff[0], (u32)(n / ECRYPT_BLOCKLENGTH));
|
||||
cb(&buff[0], n);
|
||||
//m_underlying_stream.write(&buff[0], n);
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buff.append(buf, n);
|
||||
size_t encr_count = m_buff.size() - m_buff.size() % ECRYPT_BLOCKLENGTH;
|
||||
if (!encr_count)
|
||||
return n;
|
||||
std::vector<char_type> buff(encr_count);
|
||||
ECRYPT_encrypt_blocks(&m_ctx, (u8*)m_buff.data(), (u8*)&buff[0], (u32)(m_buff.size() / ECRYPT_BLOCKLENGTH));
|
||||
//m_underlying_stream.write(&buff[0], encr_count);
|
||||
cb(&buff[0], encr_count);
|
||||
m_buff.erase(0, encr_count);
|
||||
return encr_count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename cb_handler>
|
||||
bool flush(cb_handler cb)
|
||||
{
|
||||
if (m_buff.empty())
|
||||
return true;
|
||||
|
||||
std::vector<char_type> buff(m_buff.size());
|
||||
ECRYPT_encrypt_bytes(&m_ctx, (u8*)m_buff.data(), (u8*)&buff[0], (u32)m_buff.size());
|
||||
cb(&buff[0], m_buff.size());
|
||||
//m_underlying_stream.write(&buff[0], m_buff.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const crypto::chacha8_iv& m_iv;
|
||||
mutable ECRYPT_ctx m_ctx;
|
||||
//std::ostream &m_underlying_stream;
|
||||
crypto::chacha8_key m_key;
|
||||
mutable std::string m_buff;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
class encrypt_chacha_out_filter : public encrypt_chacha_processer_base
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
struct category :
|
||||
public boost::iostreams::multichar_output_filter_tag,
|
||||
public boost::iostreams::flushable_tag
|
||||
{ };
|
||||
|
||||
encrypt_chacha_out_filter(std::string const &pass, const crypto::chacha8_iv& iv) :encrypt_chacha_processer_base(pass, iv)
|
||||
{
|
||||
}
|
||||
~encrypt_chacha_out_filter()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename t_sink>
|
||||
std::streamsize write(t_sink& snk, char_type const * const buf, std::streamsize const n) const
|
||||
{
|
||||
return encrypt_chacha_processer_base::process(buf, n, [&](char_type const * const buf_lambda, std::streamsize const n_lambda) {
|
||||
boost::iostreams::write(snk, &buf_lambda[0], n_lambda);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Sink>
|
||||
bool flush(Sink& snk)
|
||||
{
|
||||
|
||||
encrypt_chacha_processer_base::flush([&](char_type const * const buf_lambda, std::streamsize const n_lambda) {
|
||||
boost::iostreams::write(snk, &buf_lambda[0], n_lambda);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
class encrypt_chacha_in_filter : public encrypt_chacha_processer_base
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
struct category : //public boost::iostreams::seekable_device_tag,
|
||||
public boost::iostreams::multichar_input_filter_tag,
|
||||
public boost::iostreams::flushable_tag
|
||||
//public boost::iostreams::seekable_filter_tag
|
||||
{ };
|
||||
encrypt_chacha_in_filter(std::string const &pass, const crypto::chacha8_iv& iv) :encrypt_chacha_processer_base(pass, iv), m_was_eof(false)
|
||||
{
|
||||
}
|
||||
~encrypt_chacha_in_filter()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
std::streamsize read(Source& src, char* s, std::streamsize n)
|
||||
{
|
||||
if (m_buff.size() >= static_cast<size_t>(n))
|
||||
{
|
||||
return withdraw_to_read_buff(s, n);
|
||||
}
|
||||
if (m_was_eof && m_buff.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::streamsize size_to_read_for_decrypt = (n - m_buff.size());
|
||||
size_to_read_for_decrypt += size_to_read_for_decrypt % encrypt_chacha_processer_base::block_size;
|
||||
size_t offset_in_buff = m_buff.size();
|
||||
m_buff.resize(m_buff.size() + size_to_read_for_decrypt);
|
||||
|
||||
std::streamsize result = boost::iostreams::read(src, (char*)&m_buff.data()[offset_in_buff], size_to_read_for_decrypt);
|
||||
if (result == size_to_read_for_decrypt)
|
||||
{
|
||||
//regular read proocess, readed data enought to get decrypteds
|
||||
encrypt_chacha_processer_base::process(&m_buff.data()[offset_in_buff], size_to_read_for_decrypt, [&](char_type const* const buf_lambda, std::streamsize const n_lambda)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(n_lambda == size_to_read_for_decrypt, "Error in decrypt: check n_lambda == size_to_read_for_decrypt failed");
|
||||
std::memcpy((char*)&m_buff.data()[offset_in_buff], buf_lambda, n_lambda);
|
||||
});
|
||||
return withdraw_to_read_buff(s, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
//been read some size_but it's basically might be eof
|
||||
if (!m_was_eof)
|
||||
{
|
||||
size_t offset_before_flush = offset_in_buff;
|
||||
if (result != -1)
|
||||
{
|
||||
//eof
|
||||
encrypt_chacha_processer_base::process(&m_buff.data()[offset_in_buff], result, [&](char_type const* const buf_lambda, std::streamsize const n_lambda) {
|
||||
std::memcpy((char*)&m_buff.data()[offset_in_buff], buf_lambda, n_lambda);
|
||||
offset_before_flush = offset_in_buff + n_lambda;
|
||||
});
|
||||
}
|
||||
|
||||
encrypt_chacha_processer_base::flush([&](char_type const* const buf_lambda, std::streamsize const n_lambda) {
|
||||
if (n_lambda + offset_before_flush > m_buff.size())
|
||||
{
|
||||
m_buff.resize(n_lambda + offset_before_flush);
|
||||
}
|
||||
std::memcpy((char*)&m_buff.data()[offset_before_flush], buf_lambda, n_lambda);
|
||||
m_buff.resize(offset_before_flush + n_lambda);
|
||||
});
|
||||
|
||||
//just to make sure that it's over
|
||||
std::string buff_stub(10, ' ');
|
||||
std::streamsize r = boost::iostreams::read(src, (char*)&buff_stub.data()[0], 10);
|
||||
CHECK_AND_ASSERT_THROW_MES(r == -1, "expected EOF");
|
||||
m_was_eof = true;
|
||||
return withdraw_to_read_buff(s, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Sink>
|
||||
bool flush(Sink& snk)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::streamsize withdraw_to_read_buff(char* s, std::streamsize n)
|
||||
{
|
||||
|
||||
size_t copy_size = m_buff.size() > static_cast<size_t>(n) ? static_cast<size_t>(n) : m_buff.size();
|
||||
std::memcpy(s, m_buff.data(), copy_size);
|
||||
m_buff.erase(0, copy_size);
|
||||
return copy_size;
|
||||
}
|
||||
|
||||
std::string m_buff;
|
||||
bool m_was_eof;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#define API_RETURN_CODE_OK BASIC_RESPONSE_STATUS_OK
|
||||
#define API_RETURN_CODE_FAIL BASIC_RESPONSE_STATUS_FAILED
|
||||
#define API_RETURN_CODE_NOT_FOUND BASIC_RESPONSE_STATUS_NOT_FOUND
|
||||
#define API_RETURN_CODE_ACCESS_DENIED "ACCESS_DENIED"
|
||||
#define API_RETURN_CODE_INTERNAL_ERROR "INTERNAL_ERROR"
|
||||
#define API_RETURN_CODE_NOT_ENOUGH_MONEY "NOT_ENOUGH_MONEY"
|
||||
#define API_RETURN_CODE_NOT_ENOUGH_OUTPUTS_FOR_MIXING "NOT_ENOUGH_OUTPUTS_FOR_MIXING"
|
||||
#define API_RETURN_CODE_INTERNAL_ERROR_QUE_FULL "INTERNAL_ERROR_QUE_FULL"
|
||||
#define API_RETURN_CODE_BAD_ARG "BAD_ARG"
|
||||
#define API_RETURN_CODE_BAD_ARG_EMPTY_DESTINATIONS "BAD_ARG_EMPTY_DESTINATIONS"
|
||||
#define API_RETURN_CODE_BAD_ARG_WRONG_FEE "BAD_ARG_WRONG_FEE"
|
||||
#define API_RETURN_CODE_BAD_ARG_INVALID_ADDRESS "BAD_ARG_INVALID_ADDRESS"
|
||||
#define API_RETURN_CODE_BAD_ARG_WRONG_AMOUNT "BAD_ARG_WRONG_AMOUNT"
|
||||
#define API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID "BAD_ARG_WRONG_PAYMENT_ID"
|
||||
#define API_RETURN_CODE_WRONG_PASSWORD "WRONG_PASSWORD"
|
||||
#define API_RETURN_CODE_WALLET_WRONG_ID "WALLET_WRONG_ID"
|
||||
#define API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED "WALLET_WATCH_ONLY_NOT_SUPPORTED"
|
||||
#define API_RETURN_CODE_WALLET_AUDITABLE_NOT_SUPPORTED "WALLET_AUDITABLE_NOT_SUPPORTED"
|
||||
#define API_RETURN_CODE_FILE_NOT_FOUND "FILE_NOT_FOUND"
|
||||
#define API_RETURN_CODE_ALREADY_EXISTS "ALREADY_EXISTS"
|
||||
#define API_RETURN_CODE_CANCELED "CANCELED"
|
||||
#define API_RETURN_CODE_FILE_RESTORED "FILE_RESTORED"
|
||||
#define API_RETURN_CODE_TRUE "TRUE"
|
||||
#define API_RETURN_CODE_FALSE "FALSE"
|
||||
#define API_RETURN_CODE_CORE_BUSY "CORE_BUSY"
|
||||
#define API_RETURN_CODE_OVERFLOW "OVERFLOW"
|
||||
#define API_RETURN_CODE_BUSY "BUSY"
|
||||
#define API_RETURN_CODE_INVALID_FILE "INVALID_FILE"
|
||||
#define API_RETURN_CODE_WRONG_SEED "WRONG_SEED"
|
||||
#define API_RETURN_CODE_GENESIS_MISMATCH "GENESIS_MISMATCH"
|
||||
#define API_RETURN_CODE_DISCONNECTED "DISCONNECTED"
|
||||
#define API_RETURN_CODE_UNINITIALIZED "UNINITIALIZED"
|
||||
#define API_RETURN_CODE_TX_IS_TOO_BIG "TX_IS_TOO_BIG"
|
||||
#define API_RETURN_CODE_TX_REJECTED "TX_REJECTED"
|
||||
#define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED"
|
||||
#define API_RETURN_CODE_WRAP "WRAP"
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "serialization/keyvalue_hexemizer.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "storages/portable_storage_base.h"
|
||||
#include "currency_core/basic_api_response_codes.h"
|
||||
#include "common/error_codes.h"
|
||||
namespace currency
|
||||
{
|
||||
//-----------------------------------------------
|
||||
|
||||
|
||||
struct tx_cost_struct
|
||||
{
|
||||
std::string usd_needed_for_erc20;
|
||||
std::string zano_needed_for_erc20;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(usd_needed_for_erc20)
|
||||
KV_SERIALIZE(zano_needed_for_erc20)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct rpc_get_wrap_info_response
|
||||
{
|
||||
std::string unwraped_coins_left;
|
||||
tx_cost_struct tx_cost;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(unwraped_coins_left)
|
||||
KV_SERIALIZE(tx_cost)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(__ORDER_LITTLE_ENDIAN__)
|
||||
#define __ORDER_LITTLE_ENDIAN__ 1011012001
|
||||
#endif
|
||||
|
||||
#if !defined(__BYTE_ORDER__)
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#endif
|
||||
|
||||
#if !defined(__ORDER_BIG_ENDIAN__)
|
||||
#define __ORDER_BIG_ENDIAN__ 0
|
||||
#endif
|
||||
|
||||
static inline uint32_t rol32(uint32_t x, int r) {
|
||||
static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers");
|
||||
return _rotl(x, r);
|
||||
}
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int r) {
|
||||
return _rotl64(x, r);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint32_t rol32(uint32_t x, int r) {
|
||||
return (x << (r & 31)) | (x >> (-r & 31));
|
||||
}
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int r) {
|
||||
return (x << (r & 63)) | (x >> (-r & 63));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline uint64_t hi_dword(uint64_t val) {
|
||||
return val >> 32;
|
||||
}
|
||||
|
||||
static inline uint64_t lo_dword(uint64_t val) {
|
||||
return val & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline uint64_t mul128_manually(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
|
||||
// multiplier = ab = a * 2^32 + b
|
||||
// multiplicand = cd = c * 2^32 + d
|
||||
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
|
||||
uint64_t a = hi_dword(multiplier);
|
||||
uint64_t b = lo_dword(multiplier);
|
||||
uint64_t c = hi_dword(multiplicand);
|
||||
uint64_t d = lo_dword(multiplicand);
|
||||
|
||||
uint64_t ac = a * c;
|
||||
uint64_t ad = a * d;
|
||||
uint64_t bc = b * c;
|
||||
uint64_t bd = b * d;
|
||||
|
||||
uint64_t adbc = ad + bc;
|
||||
uint64_t adbc_carry = adbc < ad ? 1 : 0;
|
||||
|
||||
// multiplier * multiplicand = product_hi * 2^64 + product_lo
|
||||
uint64_t product_lo = bd + (adbc << 32);
|
||||
uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
|
||||
*product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
|
||||
assert(ac <= *product_hi);
|
||||
|
||||
return product_lo;
|
||||
}
|
||||
|
||||
static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
|
||||
dividend |= ((uint64_t)*remainder) << 32;
|
||||
*remainder = dividend % divisor;
|
||||
return dividend / divisor;
|
||||
}
|
||||
|
||||
// Long division with 2^32 base
|
||||
static inline uint32_t div128_32_manually(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
|
||||
uint64_t dividend_dwords[4];
|
||||
uint32_t remainder = 0;
|
||||
|
||||
dividend_dwords[3] = hi_dword(dividend_hi);
|
||||
dividend_dwords[2] = lo_dword(dividend_hi);
|
||||
dividend_dwords[1] = hi_dword(dividend_lo);
|
||||
dividend_dwords[0] = lo_dword(dividend_lo);
|
||||
|
||||
*quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32;
|
||||
*quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder);
|
||||
*quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32;
|
||||
*quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder);
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi)
|
||||
{
|
||||
// #if defined(_MSC_VER)
|
||||
// return _umul128(multiplier, multiplicand, product_hi);
|
||||
// #elif defined(__GNUC__)
|
||||
// __uint128_t product = ((__uint128_t)multiplier) * multiplicand;
|
||||
// *product_hi = (uint64_t)(product >> 64);
|
||||
// return ((uint64_t)product) & ~(UINT64_C(0));
|
||||
// #else
|
||||
return mul128_manually(multiplier, multiplicand, product_hi);
|
||||
//#endif*/
|
||||
}
|
||||
//*/
|
||||
|
||||
static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo)
|
||||
{
|
||||
// #if defined(__GNUC__)
|
||||
// __uint128_t dividend = (((__uint128_t)dividend_hi) << 64) | dividend_lo;
|
||||
// __uint128_t quotient = dividend / divisor;
|
||||
// __uint128_t reminder = dividend % divisor;
|
||||
// *quotient_hi = (uint64_t)(quotient >> 64);
|
||||
// *quotient_lo = ((uint64_t)quotient) & ~(UINT64_C(0));
|
||||
// return (uint32_t)reminder;
|
||||
// #else
|
||||
return div128_32_manually(dividend_hi, dividend_lo, divisor, quotient_hi, quotient_lo);
|
||||
//#endif
|
||||
}
|
||||
//*/
|
||||
#define IDENT32(x) ((uint32_t) (x))
|
||||
#define IDENT64(x) ((uint64_t) (x))
|
||||
|
||||
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
|
||||
(((uint32_t) (x) & 0x0000ff00) << 8) | \
|
||||
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
|
||||
(((uint32_t) (x) & 0xff000000) >> 24))
|
||||
#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
|
||||
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
|
||||
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
|
||||
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
|
||||
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
|
||||
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
|
||||
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
|
||||
(((uint64_t) (x) & 0xff00000000000000) >> 56))
|
||||
|
||||
static inline uint32_t ident32(uint32_t x) { return x; }
|
||||
static inline uint64_t ident64(uint64_t x) { return x; }
|
||||
|
||||
static inline uint32_t swap32(uint32_t x) {
|
||||
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||
return (x << 16) | (x >> 16);
|
||||
}
|
||||
static inline uint64_t swap64(uint64_t x) {
|
||||
x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8);
|
||||
x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16);
|
||||
return (x << 32) | (x >> 32);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
|
||||
#undef UNUSED
|
||||
|
||||
static inline void mem_inplace_swap32(void *mem, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]);
|
||||
}
|
||||
}
|
||||
static inline void mem_inplace_swap64(void *mem, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
|
||||
memcpy(dst, src, 4 * n);
|
||||
}
|
||||
static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
|
||||
memcpy(dst, src, 8 * n);
|
||||
}
|
||||
|
||||
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]);
|
||||
}
|
||||
}
|
||||
static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__ORDER_BIG_ENDIAN__)
|
||||
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define SWAP32LE IDENT32
|
||||
#define SWAP32BE SWAP32
|
||||
#define swap32le ident32
|
||||
#define swap32be swap32
|
||||
#define mem_inplace_swap32le mem_inplace_ident
|
||||
#define mem_inplace_swap32be mem_inplace_swap32
|
||||
#define memcpy_swap32le memcpy_ident32
|
||||
#define memcpy_swap32be memcpy_swap32
|
||||
#define SWAP64LE IDENT64
|
||||
#define SWAP64BE SWAP64
|
||||
#define swap64le ident64
|
||||
#define swap64be swap64
|
||||
#define mem_inplace_swap64le mem_inplace_ident
|
||||
#define mem_inplace_swap64be mem_inplace_swap64
|
||||
#define memcpy_swap64le memcpy_ident64
|
||||
#define memcpy_swap64be memcpy_swap64
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define SWAP32BE IDENT32
|
||||
#define SWAP32LE SWAP32
|
||||
#define swap32be ident32
|
||||
#define swap32le swap32
|
||||
#define mem_inplace_swap32be mem_inplace_ident
|
||||
#define mem_inplace_swap32le mem_inplace_swap32
|
||||
#define memcpy_swap32be memcpy_ident32
|
||||
#define memcpy_swap32le memcpy_swap32
|
||||
#define SWAP64BE IDENT64
|
||||
#define SWAP64LE SWAP64
|
||||
#define swap64be ident64
|
||||
#define swap64le swap64
|
||||
#define mem_inplace_swap64be mem_inplace_ident
|
||||
#define mem_inplace_swap64le mem_inplace_swap64
|
||||
#define memcpy_swap64be memcpy_ident64
|
||||
#define memcpy_swap64le memcpy_swap64
|
||||
#endif
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
#define POD_MAKE_COMPARABLE(space, type) \
|
||||
namespace space { \
|
||||
inline bool operator==(const type &_v1, const type &_v2) { \
|
||||
return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \
|
||||
} \
|
||||
inline bool operator!=(const type &_v1, const type &_v2) { \
|
||||
return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define POD_MAKE_HASHABLE(space, type) \
|
||||
POD_MAKE_COMPARABLE(space, type) \
|
||||
namespace space { \
|
||||
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
|
||||
inline std::size_t hash_value(const type &_v) { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
} \
|
||||
} \
|
||||
namespace std { \
|
||||
template<> \
|
||||
struct hash<space::type> { \
|
||||
std::size_t operator()(const space::type &_v) const { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
// this allows using std::pair<> as a key in unordered std containers
|
||||
template <class T1, class T2>
|
||||
struct hash<pair<T1, T2>>
|
||||
{
|
||||
size_t operator()(const pair<T1, T2>& p) const
|
||||
{
|
||||
auto hash1 = hash<T1>{}(p.first);
|
||||
auto hash2 = hash<T2>{}(p.second);
|
||||
return hash1 ^ hash2;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "misc_language.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
#define LOC_INT_ERR(cond, msg) CHECK_AND_ASSERT_THROW_MES(cond, "internal error in median_db_cache: " << msg << ENDL << *this)
|
||||
template<typename key, typename associated_data>
|
||||
class median_db_cache : public epee::misc_utils::median_helper<key, associated_data>
|
||||
{
|
||||
typedef epee::misc_utils::median_helper<key, associated_data> super_t;
|
||||
struct db_entry_type
|
||||
{
|
||||
key k;
|
||||
associated_data d;
|
||||
};
|
||||
|
||||
//m_tx_median_helper;
|
||||
typedef tools::db::cached_key_value_accessor<uint64_t, db_entry_type, false, true> median_db_container;
|
||||
median_db_container m_median_container;
|
||||
uint64_t m_counter_hi;
|
||||
uint64_t m_counter_lo;
|
||||
bool m_is_loading_from_db;
|
||||
|
||||
bool load_items_from_db()
|
||||
{
|
||||
std::map<uint64_t, db_entry_type> loaded_entries;
|
||||
LOG_PRINT_L0("Loading median from db cache...");
|
||||
m_median_container.enumerate_items([&](uint64_t i, uint64_t index, const db_entry_type& entry)
|
||||
{
|
||||
//adjust counters
|
||||
if (index > m_counter_hi)
|
||||
m_counter_hi = index;
|
||||
if (index < m_counter_lo)
|
||||
m_counter_lo = index;
|
||||
loaded_entries[index] = entry;
|
||||
return true;
|
||||
});
|
||||
LOG_PRINT_L0("Loaded " << loaded_entries.size() << " items, building median cache...");
|
||||
|
||||
m_is_loading_from_db = true;
|
||||
for (auto i : loaded_entries)
|
||||
{
|
||||
this->push_item(i.second.k, i.second.d);
|
||||
}
|
||||
m_is_loading_from_db = false;
|
||||
LOG_PRINT_L0("Median cache build OK");
|
||||
return true;
|
||||
}
|
||||
virtual void handle_add_front_item(const key& k, const associated_data& ad)
|
||||
{
|
||||
if (m_is_loading_from_db)
|
||||
return;
|
||||
db_entry_type det = AUTO_VAL_INIT(det);
|
||||
det.k = k;
|
||||
det.d = ad;
|
||||
m_median_container.set(++m_counter_hi, det);
|
||||
|
||||
//in case if it was totally empty at init(which is very doubtful)
|
||||
if (m_counter_lo == std::numeric_limits<uint64_t>::max())
|
||||
m_counter_lo = m_counter_hi;
|
||||
|
||||
}
|
||||
virtual void handle_remove_front_item(const key& k)
|
||||
{
|
||||
LOC_INT_ERR(!m_is_loading_from_db, "m_is_loading_from_db is true");
|
||||
LOC_INT_ERR(m_median_container.erase_validate(m_counter_hi), "erase_validate failed");
|
||||
--m_counter_hi;
|
||||
//TODO: check coretests and make a decision on what to do with the following check
|
||||
//LOC_INT_ERR(m_counter_lo <= m_counter_hi, "handle_remove_front_item: m_counter_lo(" << m_counter_lo << ") > m_counter_hi(" << m_counter_hi << ")");
|
||||
}
|
||||
virtual void handle_purge_back_item()
|
||||
{
|
||||
LOC_INT_ERR(m_counter_lo < m_counter_hi, "handle_purge_back_item: m_counter_lo(" << m_counter_lo << ") >= m_counter_hi(" << m_counter_hi << ")");
|
||||
m_median_container.erase(m_counter_lo++);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
median_db_cache(db::basic_db_accessor& db) :
|
||||
m_median_container(db),
|
||||
m_counter_hi(0),
|
||||
m_counter_lo(std::numeric_limits<uint64_t>::max()),
|
||||
m_is_loading_from_db(false)
|
||||
{
|
||||
|
||||
}
|
||||
bool init(const std::string& name)
|
||||
{
|
||||
bool r = m_median_container.init(name);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to init m_median_container");
|
||||
return load_items_from_db();
|
||||
}
|
||||
|
||||
~median_db_cache()
|
||||
{
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
super_t::clear();
|
||||
m_median_container.clear();
|
||||
m_counter_hi = 0;
|
||||
m_counter_lo = std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
friend std::ostream& operator<<(std::ostream& ss, const median_db_cache<key_t, associated_data_t> &mdbc);
|
||||
}; // class median_db_cache
|
||||
#undef LOC_INT_ERR
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
inline std::ostream& operator<<(std::ostream& s, const median_db_cache<key_t, associated_data_t> &mdbc)
|
||||
{
|
||||
s << "median_db_cache<" << typeid(key_t).name() << ", " << typeid(associated_data_t).name() << "> instance 0x" << &mdbc << ENDL
|
||||
<< " m_counter_lo: " << mdbc.m_counter_lo << ENDL
|
||||
<< " m_counter_hi: " << mdbc.m_counter_hi << ENDL
|
||||
<< " m_is_loading_from_db: " << mdbc.m_is_loading_from_db << ENDL
|
||||
<< " m_median_container.size: " << mdbc.m_median_container.size() << ENDL
|
||||
<< " m_median_container.size_no_cache(): " << mdbc.m_median_container.size_no_cache() << ENDL
|
||||
<< "parent " << static_cast<epee::misc_utils::median_helper<key_t, associated_data_t>>(mdbc);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <boost/thread.hpp>
|
||||
#include "include_base_utils.h"
|
||||
extern "C" {
|
||||
#include "miniupnp/miniupnpc/miniupnpc.h"
|
||||
#include "miniupnp/miniupnpc/upnpcommands.h"
|
||||
#include "miniupnp/miniupnpc/upnperrors.h"
|
||||
}
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
class miniupnp_helper
|
||||
{
|
||||
UPNPDev *m_devlist;
|
||||
UPNPUrls m_urls;
|
||||
IGDdatas m_data;
|
||||
char m_lanaddr[64];
|
||||
int m_IGD;
|
||||
boost::thread m_mapper_thread;
|
||||
boost::thread m_initializer_thread;
|
||||
uint32_t m_external_port;
|
||||
uint32_t m_internal_port;
|
||||
uint32_t m_period_ms;
|
||||
public:
|
||||
miniupnp_helper():m_devlist(nullptr),
|
||||
m_urls(AUTO_VAL_INIT(m_urls)),
|
||||
m_data(AUTO_VAL_INIT(m_data)),
|
||||
m_IGD(0),
|
||||
m_external_port(0),
|
||||
m_internal_port(0),
|
||||
m_period_ms(0)
|
||||
{
|
||||
m_lanaddr[0] = 0;
|
||||
}
|
||||
~miniupnp_helper()
|
||||
{
|
||||
NESTED_TRY_ENTRY();
|
||||
|
||||
deinit();
|
||||
|
||||
NESTED_CATCH_ENTRY(__func__);
|
||||
}
|
||||
|
||||
bool start_regular_mapping(uint32_t internal_port, uint32_t external_port, uint32_t period_ms)
|
||||
{
|
||||
m_external_port = external_port;
|
||||
m_internal_port = internal_port;
|
||||
m_period_ms = period_ms;
|
||||
if(!init())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stop_mapping()
|
||||
{
|
||||
if(m_mapper_thread.joinable())
|
||||
{
|
||||
m_mapper_thread.interrupt();
|
||||
m_mapper_thread.join();
|
||||
}
|
||||
|
||||
if(m_IGD == 1)
|
||||
{
|
||||
do_port_unmapping();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool init()
|
||||
{
|
||||
m_initializer_thread = boost::thread([=]()
|
||||
{
|
||||
deinit();
|
||||
|
||||
int error = 0;
|
||||
m_devlist = upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &error);
|
||||
if (error)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to call upnpDiscover");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_IGD = UPNP_GetValidIGD(m_devlist, &m_urls, &m_data, m_lanaddr, sizeof(m_lanaddr));
|
||||
if (m_IGD != 1)
|
||||
{
|
||||
LOG_PRINT_L2("IGD not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mapper_thread = boost::thread([=]() {run_port_mapping_loop(m_internal_port, m_external_port, m_period_ms); });
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool deinit()
|
||||
{
|
||||
if(m_initializer_thread.get_id() != boost::this_thread::get_id())
|
||||
{
|
||||
if (m_initializer_thread.joinable())
|
||||
{
|
||||
m_initializer_thread.interrupt();
|
||||
m_initializer_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
stop_mapping();
|
||||
|
||||
if(m_devlist)
|
||||
{
|
||||
freeUPNPDevlist(m_devlist);
|
||||
m_devlist = nullptr;
|
||||
}
|
||||
|
||||
if(m_IGD > 0)
|
||||
{
|
||||
FreeUPNPUrls(&m_urls);
|
||||
m_IGD = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_port_mapping_loop(uint32_t internal_port, uint32_t external_port, uint32_t period_ms)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
do_port_mapping(external_port, internal_port);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds( period_ms ));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_port_mapping(uint32_t external_port, uint32_t internal_port)
|
||||
{
|
||||
std::string internal_port_str = std::to_string(internal_port);
|
||||
std::string external_port_str = std::to_string(external_port);
|
||||
std::string str_desc = CURRENCY_NAME " v" PROJECT_VERSION_LONG;
|
||||
|
||||
int r = UPNP_AddPortMapping(m_urls.controlURL, m_data.first.servicetype,
|
||||
external_port_str.c_str(), internal_port_str.c_str(), m_lanaddr, str_desc.c_str(), "TCP", nullptr, "0");
|
||||
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LOG_PRINT_L1("AddPortMapping with external_port_str= " << external_port_str <<
|
||||
", internal_port_str=" << internal_port_str <<
|
||||
", failed with code=" << r << "(" << strupnperror(r) << ")");
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("[upnp] port mapped successful (ext: " << external_port_str << ", int:" << internal_port_str << ")");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_port_unmapping()
|
||||
{
|
||||
std::string external_port_str = std::to_string(m_external_port);
|
||||
|
||||
int r = UPNP_DeletePortMapping(m_urls.controlURL, m_data.first.servicetype, external_port_str.c_str(), "TCP", nullptr);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LOG_PRINT_L1("DeletePortMapping with external_port_str= " << external_port_str <<
|
||||
", failed with code=" << r << "(" << strupnperror(r) << ")");
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("[upnp] port unmapped successful (ext: " << external_port_str << ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) 2014, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
* This file and its cpp file are for translating Electrum-style word lists
|
||||
* into their equivalent byte representations for cross-compatibility with
|
||||
* that method of "backing up" one's wallet keys.
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace mnemonic_encoding
|
||||
{
|
||||
constexpr int NUMWORDS = 1626;
|
||||
|
||||
std::vector<unsigned char> text2binary(const std::string& text);
|
||||
std::string binary2text(const std::vector<unsigned char>& binary);
|
||||
std::string word_by_num(uint32_t n);
|
||||
uint64_t num_by_word(const std::string& w);
|
||||
bool valid_word(const std::string& w);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
|
||||
// Note: class udp_blocking_client is a slightly modified version of an example
|
||||
// taken from https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_udp_client.cpp
|
||||
//
|
||||
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <epee/include/misc_log_ex.h>
|
||||
#include <chrono>
|
||||
#include "ntp.h"
|
||||
|
||||
using boost::asio::deadline_timer;
|
||||
using boost::asio::ip::udp;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// This class manages socket timeouts by applying the concept of a deadline.
|
||||
// Each asynchronous operation is given a deadline by which it must complete.
|
||||
// Deadlines are enforced by an "actor" that persists for the lifetime of the
|
||||
// client object:
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | check_deadline |<---+
|
||||
// | | |
|
||||
// +----------------+ | async_wait()
|
||||
// | |
|
||||
// +---------+
|
||||
//
|
||||
// If the actor determines that the deadline has expired, any outstanding
|
||||
// socket operations are cancelled. The socket operations themselves are
|
||||
// implemented as transient actors:
|
||||
//
|
||||
// +---------------+
|
||||
// | |
|
||||
// | receive |
|
||||
// | |
|
||||
// +---------------+
|
||||
// |
|
||||
// async_- | +----------------+
|
||||
// receive() | | |
|
||||
// +--->| handle_receive |
|
||||
// | |
|
||||
// +----------------+
|
||||
//
|
||||
// The client object runs the io_service to block thread execution until the
|
||||
// actor completes.
|
||||
//
|
||||
namespace
|
||||
{
|
||||
class udp_blocking_client
|
||||
{
|
||||
public:
|
||||
udp_blocking_client(const udp::endpoint& listen_endpoint, udp::socket& socket, boost::asio::io_service& io_service)
|
||||
: socket_(socket),
|
||||
io_service_(io_service),
|
||||
deadline_(io_service)
|
||||
{
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
check_deadline();
|
||||
}
|
||||
|
||||
std::size_t receive(const boost::asio::mutable_buffer& buffer,
|
||||
boost::posix_time::time_duration timeout, boost::system::error_code& ec)
|
||||
{
|
||||
// Set a deadline for the asynchronous operation.
|
||||
deadline_.expires_from_now(timeout);
|
||||
|
||||
// Set up the variables that receive the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
// operation is incomplete. Asio guarantees that its asynchronous
|
||||
// operations will never fail with would_block, so any other value in
|
||||
// ec indicates completion.
|
||||
ec = boost::asio::error::would_block;
|
||||
std::size_t length = 0;
|
||||
|
||||
// Start the asynchronous operation itself. The handle_receive function
|
||||
// used as a callback will update the ec and length variables.
|
||||
socket_.async_receive(boost::asio::buffer(buffer),
|
||||
boost::bind(&udp_blocking_client::handle_receive, _1, _2, &ec, &length));
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private:
|
||||
void check_deadline()
|
||||
{
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
|
||||
{
|
||||
// The deadline has passed. The outstanding asynchronous operation needs
|
||||
// to be cancelled so that the blocked receive() function will return.
|
||||
//
|
||||
// Please note that cancel() has portability issues on some versions of
|
||||
// Microsoft Windows, and it may be necessary to use close() instead.
|
||||
// Consult the documentation for cancel() for further information.
|
||||
socket_.cancel();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
// Put the actor back to sleep.
|
||||
deadline_.async_wait(boost::bind(&udp_blocking_client::check_deadline, this));
|
||||
}
|
||||
|
||||
static void handle_receive(
|
||||
const boost::system::error_code& ec, std::size_t length,
|
||||
boost::system::error_code* out_ec, std::size_t* out_length)
|
||||
{
|
||||
*out_ec = ec;
|
||||
*out_length = length;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service& io_service_;
|
||||
udp::socket& socket_;
|
||||
deadline_timer deadline_;
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ntp_packet
|
||||
{
|
||||
|
||||
uint8_t li_vn_mode; // Eight bits. li, vn, and mode.
|
||||
// li. Two bits. Leap indicator.
|
||||
// vn. Three bits. Version number of the protocol.
|
||||
// mode. Three bits. Client will pick mode 3 for client.
|
||||
|
||||
uint8_t stratum; // Eight bits. Stratum level of the local clock.
|
||||
uint8_t poll; // Eight bits. Maximum interval between successive messages.
|
||||
uint8_t precision; // Eight bits. Precision of the local clock.
|
||||
|
||||
uint32_t rootDelay; // 32 bits. Total round trip delay time.
|
||||
uint32_t rootDispersion; // 32 bits. Max error aloud from primary clock source.
|
||||
uint32_t refId; // 32 bits. Reference clock identifier.
|
||||
|
||||
uint32_t refTm_s; // 32 bits. Reference time-stamp seconds.
|
||||
uint32_t refTm_f; // 32 bits. Reference time-stamp fraction of a second.
|
||||
|
||||
uint64_t orig_tm; // 64 bits. Originate time-stamp (set by client)
|
||||
|
||||
uint32_t rxTm_s; // 32 bits. Received time-stamp seconds.
|
||||
uint32_t rxTm_f; // 32 bits. Received time-stamp fraction of a second.
|
||||
|
||||
uint32_t txTm_s; // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
|
||||
uint32_t txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
|
||||
|
||||
}; // Total: 384 bits or 48 bytes.
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(ntp_packet) == 48, "ntp_packet has invalid size");
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
int64_t get_ntp_time(const std::string& host_name, size_t timeout_sec)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::resolver resolver(io_service);
|
||||
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), host_name, "ntp");
|
||||
boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
|
||||
boost::asio::ip::udp::socket socket(io_service);
|
||||
socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
ntp_packet packet_sent = AUTO_VAL_INIT(packet_sent);
|
||||
packet_sent.li_vn_mode = 0x1b;
|
||||
auto packet_sent_time = std::chrono::high_resolution_clock::now();
|
||||
socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint);
|
||||
|
||||
ntp_packet packet_received = AUTO_VAL_INIT(packet_received);
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
|
||||
udp_blocking_client ubc(sender_endpoint, socket, io_service);
|
||||
boost::system::error_code ec;
|
||||
ubc.receive(boost::asio::buffer(&packet_received, sizeof packet_received), boost::posix_time::seconds(static_cast<long>(timeout_sec)), ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): boost error: " << ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto packet_received_time = std::chrono::high_resolution_clock::now();
|
||||
int64_t roundtrip_mcs = std::chrono::duration_cast<std::chrono::microseconds>(packet_received_time - packet_sent_time).count();
|
||||
uint64_t roundtrip_s = roundtrip_mcs > 2000000 ? roundtrip_mcs / 2000000 : 0;
|
||||
|
||||
time_t ntp_time = ntohl(packet_received.txTm_s);
|
||||
if (ntp_time <= 2208988800U)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): wrong txTm_s: " << packet_received.txTm_s);
|
||||
return 0;
|
||||
}
|
||||
// LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): RAW time received: " << ntp_time << ", refTm_s: " << ntohl(packet_received.refTm_s) << ", stratum: " << packet_received.stratum << ", round: " << roundtrip_mcs);
|
||||
ntp_time -= 2208988800U; // Unix time starts from 01/01/1970 == 2208988800U
|
||||
ntp_time += roundtrip_s;
|
||||
return ntp_time;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): exception: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): unknown exception");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TIME_SYNC_NTP_SERVERS "time1.google.com", "time2.google.com", "time3.google.com", "time4.google.com" /* , "pool.ntp.org" -- we need to request a vender zone before using this pool */
|
||||
#define TIME_SYNC_NTP_TIMEOUT_SEC 5
|
||||
#define TIME_SYNC_NTP_ATTEMPTS_COUNT 3 // max number of attempts when getting time from NTP server
|
||||
|
||||
int64_t get_ntp_time()
|
||||
{
|
||||
static const std::vector<std::string> ntp_servers { TIME_SYNC_NTP_SERVERS };
|
||||
|
||||
for (size_t att = 0; att < TIME_SYNC_NTP_ATTEMPTS_COUNT; ++att)
|
||||
{
|
||||
const std::string& ntp_server = ntp_servers[att % ntp_servers.size()];
|
||||
LOG_PRINT_L3("NTP: trying to get time from " << ntp_server);
|
||||
int64_t time = get_ntp_time(ntp_server, TIME_SYNC_NTP_TIMEOUT_SEC);
|
||||
if (time > 0)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: " << ntp_server << " responded with " << time << " (" << epee::misc_utils::get_time_str_v2(time) << ")");
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_PRINT_RED("NTP: unable to get time from NTP with " << TIME_SYNC_NTP_ATTEMPTS_COUNT << " trials", LOG_LEVEL_2);
|
||||
return 0; // smth went wrong
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
// requests current time via NTP from 'host_hame' using 'timeout_sec'
|
||||
// may return zero -- means error
|
||||
int64_t get_ntp_time(const std::string& host_name, size_t timeout_sec = 5);
|
||||
|
||||
// request time via predefined NTP servers
|
||||
// may return zero -- mean error
|
||||
int64_t get_ntp_time();
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
// in C++ no difference 'class' vs 'struct' except the default members access.
|
||||
// maybe be better to erase the 'POD_CLASS' macro completely?
|
||||
#define POD_CLASS struct
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
template<typename pod_t>
|
||||
class pod_array_file_container
|
||||
{
|
||||
public:
|
||||
pod_array_file_container()
|
||||
{}
|
||||
|
||||
~pod_array_file_container()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool open(const std::wstring& filename, bool create_if_not_exist, bool* p_corrupted = nullptr, std::string* p_reason = nullptr)
|
||||
{
|
||||
if (!create_if_not_exist && !boost::filesystem::exists(filename))
|
||||
{
|
||||
if (p_reason)
|
||||
*p_reason = "file doest not exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stream.open(filename, std::ios::binary | std::ios::app | std::ios::in);
|
||||
if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)
|
||||
{
|
||||
if (p_reason)
|
||||
*p_reason = "file could not be opened";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_corrupted)
|
||||
*p_corrupted = false;
|
||||
|
||||
size_t file_size = size_bytes();
|
||||
if (file_size % sizeof(pod_t) != 0)
|
||||
{
|
||||
// currupted
|
||||
if (p_corrupted)
|
||||
*p_corrupted = true;
|
||||
|
||||
size_t corrected_size = file_size - file_size % sizeof(pod_t);
|
||||
|
||||
// truncate to nearest item boundary
|
||||
close();
|
||||
boost::filesystem::resize_file(filename, corrected_size);
|
||||
m_stream.open(filename, std::ios::binary | std::ios::app | std::ios::in);
|
||||
if ((m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit) ||
|
||||
size_bytes() != corrected_size)
|
||||
{
|
||||
if (p_reason)
|
||||
*p_reason = "truncation failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_reason)
|
||||
*p_reason = std::string("file was corrupted, truncated: ") + epee::string_tools::num_to_string_fast(file_size) + " -> " + epee::string_tools::num_to_string_fast(corrected_size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_stream.close();
|
||||
}
|
||||
|
||||
bool push_back(const pod_t& item)
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
return false;
|
||||
|
||||
m_stream.seekp(0, std::ios_base::end);
|
||||
m_stream.write(reinterpret_cast<const char*>(&item), sizeof item);
|
||||
|
||||
if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)
|
||||
return false;
|
||||
|
||||
m_stream.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_item(size_t index, pod_t& result) const
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
return false;
|
||||
|
||||
size_t offset = index * sizeof result;
|
||||
m_stream.seekg(offset);
|
||||
if (m_stream.rdstate() != std::ios::goodbit)
|
||||
return false;
|
||||
|
||||
m_stream.read(reinterpret_cast<char*>(&result), sizeof result);
|
||||
|
||||
return m_stream.gcount() == sizeof result;
|
||||
}
|
||||
|
||||
size_t size_bytes() const
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
return 0;
|
||||
|
||||
m_stream.seekg(0, std::ios_base::end);
|
||||
return m_stream.tellg();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_bytes() / sizeof(pod_t);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable boost::filesystem::fstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
// Copyright (c) 2020 Zano Project
|
||||
// Copyright (c) 2012-2018 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include "net/http_client.h"
|
||||
#include "db_backend_selector.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "currency_core/currency_core.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
struct pre_download_entry
|
||||
{
|
||||
const char* url;
|
||||
const char* hash;
|
||||
uint64_t packed_size;
|
||||
uint64_t unpacked_size;
|
||||
};
|
||||
|
||||
#ifndef TESTNET
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_1161000.pak", "26660ffcdaf80a43a586e64a1a6da042dcb9ff3b58e14ce1ec9a775b995dc146", 1330022593, 2684313600 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_1161000.pak", "9dd03f08dea396fe32e6483a8221b292be35fa41c29748f119f11c3275956cdc", 1787475468, 2600247296 };
|
||||
#else
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
|
||||
#endif
|
||||
|
||||
static constexpr uint64_t pre_download_min_size_difference = 512 * 1024 * 1024; // minimum difference in size between local DB and the downloadable one to start downloading
|
||||
|
||||
template<class callback_t>
|
||||
bool process_predownload(const boost::program_options::variables_map& vm, callback_t cb_should_stop)
|
||||
{
|
||||
tools::db::db_backend_selector dbbs;
|
||||
bool r = dbbs.init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "db_backend_selector failed to initialize");
|
||||
|
||||
std::string config_folder = dbbs.get_config_folder();
|
||||
std::string working_folder = dbbs.get_db_folder_path();
|
||||
std::string db_main_file_path = working_folder + "/" + dbbs.get_db_main_file_name();
|
||||
|
||||
pre_download_entry pre_download = dbbs.get_engine_type() == db::db_lmdb ? c_pre_download_lmdb : c_pre_download_mdbx;
|
||||
|
||||
// override pre-download link if necessary
|
||||
std::string url = pre_download.url;
|
||||
if (command_line::has_arg(vm, command_line::arg_predownload_link))
|
||||
url = command_line::get_arg(vm, command_line::arg_predownload_link);
|
||||
|
||||
boost::system::error_code ec;
|
||||
uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec);
|
||||
bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload);
|
||||
if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) )
|
||||
{
|
||||
LOG_PRINT_MAGENTA("Pre-downloading not needed (db file size = " << sz << ")", LOG_LEVEL_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// okay, let's download
|
||||
|
||||
|
||||
std::string downloading_file_path = db_main_file_path + ".download";
|
||||
|
||||
LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0);
|
||||
epee::net_utils::http::interruptible_http_client cl;
|
||||
|
||||
crypto::stream_cn_hash hash_stream;
|
||||
auto last_update = std::chrono::system_clock::now();
|
||||
|
||||
auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes)
|
||||
{
|
||||
if (cb_should_stop(total_bytes, received_bytes))
|
||||
{
|
||||
LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
hash_stream.update(buff.data(), buff.size());
|
||||
|
||||
auto dif = std::chrono::system_clock::now() - last_update;
|
||||
if (dif >= std::chrono::milliseconds(300))
|
||||
{
|
||||
boost::io::ios_flags_saver ifs(std::cout);
|
||||
std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r";
|
||||
last_update = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
tools::create_directories_if_necessary(working_folder);
|
||||
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
|
||||
if (!r)
|
||||
{
|
||||
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
|
||||
return !flag_force_predownload; // fatal error only if force-predownload
|
||||
}
|
||||
|
||||
crypto::hash data_hash = hash_stream.calculate_hash();
|
||||
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
|
||||
{
|
||||
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
|
||||
return !flag_force_predownload; // fatal error only if force-predownload
|
||||
}
|
||||
|
||||
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0);
|
||||
|
||||
if (!command_line::has_arg(vm, command_line::arg_validate_predownload))
|
||||
{
|
||||
boost::filesystem::remove(db_main_file_path, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Failed to remove " << db_main_file_path);
|
||||
return false;
|
||||
}
|
||||
LOG_PRINT_L1("Removed " << db_main_file_path);
|
||||
|
||||
boost::filesystem::rename(downloading_file_path, db_main_file_path, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Failed to rename " << downloading_file_path << " -> " << db_main_file_path);
|
||||
return false;
|
||||
}
|
||||
LOG_PRINT_L1("Renamed " << downloading_file_path << " -> " << db_main_file_path);
|
||||
|
||||
LOG_PRINT_GREEN("Blockchain successfully replaced with the new pre-downloaded data file", LOG_LEVEL_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// paranoid mode
|
||||
// move downloaded blockchain into a temporary folder
|
||||
//
|
||||
LOG_PRINT_MAGENTA(ENDL << "Downloaded blockchain database is about to be validated and added to the local database block-by-block" << ENDL, LOG_LEVEL_0);
|
||||
std::string path_to_temp_datafolder = dbbs.get_temp_config_folder();
|
||||
std::string path_to_temp_blockchain = dbbs.get_temp_db_folder_path();
|
||||
std::string path_to_temp_blockchain_file = path_to_temp_blockchain + "/" + dbbs.get_db_main_file_name();
|
||||
|
||||
tools::create_directories_if_necessary(path_to_temp_blockchain);
|
||||
boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove old blockchain database from disk
|
||||
boost::filesystem::remove_all(working_folder, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Failed to remove all from " << working_folder);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string pool_db_path = dbbs.get_pool_db_folder_path();
|
||||
boost::filesystem::remove_all(pool_db_path, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Failed to remove all from " << pool_db_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// source core
|
||||
currency::core source_core(nullptr);
|
||||
boost::program_options::variables_map source_core_vm;
|
||||
source_core_vm.insert(std::make_pair("data-dir", boost::program_options::variable_value(path_to_temp_datafolder, false)));
|
||||
source_core_vm.insert(std::make_pair("db-engine", boost::program_options::variable_value(dbbs.get_engine_name(), false)));
|
||||
//source_core_vm.insert(std::make_pair("db-sync-mode", boost::program_options::variable_value(std::string("fast"), false)));
|
||||
|
||||
r = source_core.init(source_core_vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to init source core");
|
||||
|
||||
// target core
|
||||
currency::core target_core(nullptr);
|
||||
boost::program_options::variables_map target_core_vm(vm);
|
||||
target_core_vm.insert(std::make_pair("db-engine", boost::program_options::variable_value(dbbs.get_engine_name(), false)));
|
||||
//vm_with_fast_sync.insert(std::make_pair("db-sync-mode", boost::program_options::variable_value(std::string("fast"), false)));
|
||||
|
||||
r = target_core.init(target_core_vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to init target core");
|
||||
|
||||
CHECK_AND_ASSERT_MES(target_core.get_top_block_height() == 0, false, "Target blockchain initialized not empty");
|
||||
uint64_t total_blocks = source_core.get_current_blockchain_size();
|
||||
|
||||
LOG_PRINT_GREEN("Manually processing blocks from 1 to " << total_blocks << "...", LOG_LEVEL_0);
|
||||
|
||||
for (uint64_t i = 1; i != total_blocks; i++)
|
||||
{
|
||||
std::list<currency::block> blocks;
|
||||
std::list<currency::transaction> txs;
|
||||
bool r = source_core.get_blocks(i, 1, blocks, txs);
|
||||
CHECK_AND_ASSERT_MES(r && blocks.size()==1, false, "Failed to get block " << i << " from core");
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
crypto::hash tx_hash = AUTO_VAL_INIT(tx_hash);
|
||||
for (auto& tx : txs)
|
||||
{
|
||||
r = target_core.handle_incoming_tx(tx, tvc, true /* kept_by_block */);
|
||||
CHECK_AND_ASSERT_MES(r && tvc.m_added_to_pool == true, false, "Failed to add a tx from block " << i << " from core");
|
||||
}
|
||||
currency::block_verification_context bvc = AUTO_VAL_INIT(bvc);
|
||||
r = target_core.handle_incoming_block(*blocks.begin(), bvc);
|
||||
CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain == true, false, "Failed to add block " << i << " to core");
|
||||
if (!(i % 100))
|
||||
std::cout << "Block " << i << "(" << (i * 100) / total_blocks << "%) \r";
|
||||
|
||||
if (cb_should_stop(total_blocks, i))
|
||||
{
|
||||
LOG_PRINT_MAGENTA(ENDL << "Interrupting updating db...", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_PRINT_GREEN("Processing finished, " << total_blocks << " successfully added.", LOG_LEVEL_0);
|
||||
target_core.deinit();
|
||||
source_core.deinit();
|
||||
|
||||
boost::filesystem::remove_all(path_to_temp_datafolder, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR("Failed to remove all from " << path_to_temp_datafolder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/split_free.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void save(Archive &a, const std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v.first;
|
||||
a << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void load(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
h_key k;
|
||||
hval v;
|
||||
a >> k;
|
||||
a >> v;
|
||||
x.insert(std::pair<h_key, hval>(k, v));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void save(Archive &a, const std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v.first;
|
||||
a << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void load(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
h_key k;
|
||||
hval v;
|
||||
a >> k;
|
||||
a >> v;
|
||||
x.emplace(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void save(Archive &a, const std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void load(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
hval v;
|
||||
a >> v;
|
||||
x.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,754 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "zlib_helper.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "util.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <strsafe.h>
|
||||
#include <lm.h>
|
||||
#pragma comment(lib, "netapi32.lib")
|
||||
#else
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "string_coding.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::function<void(void)> signal_handler::m_handler;
|
||||
std::function<void(int, void*)> signal_handler::m_fatal_handler;
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
bool GetWinMajorMinorVersion(DWORD& major, DWORD& minor)
|
||||
{
|
||||
bool bRetCode = false;
|
||||
LPBYTE pinfoRawData = 0;
|
||||
if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData))
|
||||
{
|
||||
WKSTA_INFO_100* pworkstationInfo = (WKSTA_INFO_100*)pinfoRawData;
|
||||
major = pworkstationInfo->wki100_ver_major;
|
||||
minor = pworkstationInfo->wki100_ver_minor;
|
||||
::NetApiBufferFree(pinfoRawData);
|
||||
bRetCode = true;
|
||||
}
|
||||
return bRetCode;
|
||||
}
|
||||
|
||||
|
||||
std::string get_windows_version_display_string()
|
||||
{
|
||||
std::string winver;
|
||||
OSVERSIONINFOEX osver;
|
||||
SYSTEM_INFO sysInfo;
|
||||
typedef void(__stdcall *GETSYSTEMINFO) (LPSYSTEM_INFO);
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4996)
|
||||
memset(&osver, 0, sizeof(osver));
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
GetVersionEx((LPOSVERSIONINFO)&osver);
|
||||
#pragma warning (pop)
|
||||
DWORD major = 0;
|
||||
DWORD minor = 0;
|
||||
if (GetWinMajorMinorVersion(major, minor))
|
||||
{
|
||||
osver.dwMajorVersion = major;
|
||||
osver.dwMinorVersion = minor;
|
||||
}
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi;
|
||||
ULONGLONG cm = 0;
|
||||
cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL);
|
||||
ZeroMemory(&osvi, sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
osvi.dwMinorVersion = 3;
|
||||
if (VerifyVersionInfoW(&osvi, VER_MINORVERSION, cm))
|
||||
{
|
||||
osver.dwMinorVersion = 3;
|
||||
}
|
||||
}
|
||||
|
||||
GETSYSTEMINFO getSysInfo = (GETSYSTEMINFO)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
|
||||
if (getSysInfo == NULL) getSysInfo = ::GetSystemInfo;
|
||||
getSysInfo(&sysInfo);
|
||||
|
||||
if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows 10 Server";
|
||||
else if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 10";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012 R2";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8.1";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008 R2";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 7";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows Vista";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION
|
||||
&& sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
winver = "Windows XP x64";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2) winver = "Windows Server 2003";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1) winver = "Windows XP";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) winver = "Windows 2000";
|
||||
else winver = "unknown";
|
||||
|
||||
if (osver.wServicePackMajor != 0)
|
||||
{
|
||||
std::string sp;
|
||||
char buf[128] = { 0 };
|
||||
sp = " Service Pack ";
|
||||
sprintf_s(buf, sizeof(buf), "%hd", osver.wServicePackMajor);
|
||||
sp.append(buf);
|
||||
winver += sp;
|
||||
}
|
||||
|
||||
if (osver.dwMajorVersion >= 6)
|
||||
{
|
||||
if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
winver += ", 64-bit";
|
||||
else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
|
||||
winver += ", 32-bit";
|
||||
}
|
||||
|
||||
|
||||
winver += "("
|
||||
+ std::to_string(osver.dwMajorVersion) + ":"
|
||||
+ std::to_string(osver.dwMinorVersion) + ":"
|
||||
+ std::to_string(osver.dwBuildNumber) + ":"
|
||||
+ std::to_string(osver.dwPlatformId) + ":"
|
||||
+ std::to_string(osver.wServicePackMajor) + ":"
|
||||
+ std::to_string(osver.wServicePackMinor) + ":"
|
||||
+ std::to_string(osver.wSuiteMask) + ":"
|
||||
+ std::to_string(osver.wProductType) + ")";
|
||||
|
||||
return winver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string get_windows_version_display_string_()
|
||||
{
|
||||
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
|
||||
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
|
||||
#define BUFSIZE 10000
|
||||
|
||||
char pszOS[BUFSIZE] = {0};
|
||||
OSVERSIONINFOEX osvi;
|
||||
SYSTEM_INFO si;
|
||||
PGNSI pGNSI;
|
||||
PGPI pGPI;
|
||||
BOOL bOsVersionInfoEx;
|
||||
DWORD dwType;
|
||||
|
||||
ZeroMemory(&si, sizeof(SYSTEM_INFO));
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
||||
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
|
||||
|
||||
if(!bOsVersionInfoEx) return pszOS;
|
||||
|
||||
// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
|
||||
|
||||
pGNSI = (PGNSI) GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetNativeSystemInfo");
|
||||
if(NULL != pGNSI)
|
||||
pGNSI(&si);
|
||||
else GetSystemInfo(&si);
|
||||
|
||||
if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
|
||||
osvi.dwMajorVersion > 4 )
|
||||
{
|
||||
StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
|
||||
|
||||
// Test for the specific product.
|
||||
|
||||
if ( osvi.dwMajorVersion == 6 )
|
||||
{
|
||||
if( osvi.dwMinorVersion == 0 )
|
||||
{
|
||||
if( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
|
||||
}
|
||||
|
||||
if ( osvi.dwMinorVersion == 1 )
|
||||
{
|
||||
if( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
|
||||
}
|
||||
|
||||
pGPI = (PGPI) GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetProductInfo");
|
||||
|
||||
pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
|
||||
|
||||
switch( dwType )
|
||||
{
|
||||
case PRODUCT_ULTIMATE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
|
||||
break;
|
||||
case PRODUCT_PROFESSIONAL:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
|
||||
break;
|
||||
case PRODUCT_BUSINESS:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
|
||||
break;
|
||||
case PRODUCT_STARTER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
|
||||
break;
|
||||
case PRODUCT_CLUSTER_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
|
||||
{
|
||||
if( GetSystemMetrics(SM_SERVERR2) )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
|
||||
else if( osvi.wProductType == VER_NT_WORKSTATION &&
|
||||
si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
|
||||
}
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
|
||||
|
||||
// Test for the server type.
|
||||
if ( osvi.wProductType != VER_NT_WORKSTATION )
|
||||
{
|
||||
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
|
||||
}
|
||||
|
||||
else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
|
||||
if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));
|
||||
|
||||
if ( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
|
||||
}
|
||||
}
|
||||
|
||||
// Include service pack (if any) and build number.
|
||||
|
||||
if( strlen(osvi.szCSDVersion) > 0 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
|
||||
StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
|
||||
}
|
||||
|
||||
TCHAR buf[80];
|
||||
|
||||
StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
|
||||
StringCchCat(pszOS, BUFSIZE, buf);
|
||||
|
||||
if ( osvi.dwMajorVersion >= 6 )
|
||||
{
|
||||
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
|
||||
else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
|
||||
}
|
||||
|
||||
return pszOS;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "This sample does not support this version of Windows.\n");
|
||||
return pszOS;
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler::GenerateCrashDump(EXCEPTION_POINTERS *pep /* = NULL*/)
|
||||
{
|
||||
SYSTEMTIME sysTime = { 0 };
|
||||
GetSystemTime(&sysTime);
|
||||
// get the computer name
|
||||
char compName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||
DWORD compNameLen = ARRAYSIZE(compName);
|
||||
GetComputerNameA(compName, &compNameLen);
|
||||
// build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP
|
||||
char path[MAX_PATH*10] = { 0 };
|
||||
std::string folder = epee::log_space::log_singletone::get_default_log_folder();
|
||||
sprintf_s(path, ARRAYSIZE(path),"%s\\crashdump_" PROJECT_VERSION_LONG "_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp",
|
||||
folder.c_str(), compName, sysTime.wYear, sysTime.wMonth, sysTime.wDay,
|
||||
sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
|
||||
|
||||
HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
// Create the minidump
|
||||
MINIDUMP_EXCEPTION_INFORMATION mdei;
|
||||
|
||||
mdei.ThreadId = GetCurrentThreadId();
|
||||
mdei.ExceptionPointers = pep;
|
||||
mdei.ClientPointers = FALSE;
|
||||
|
||||
MINIDUMP_CALLBACK_INFORMATION mci;
|
||||
|
||||
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
|
||||
mci.CallbackParam = 0;
|
||||
|
||||
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
|
||||
MiniDumpWithDataSegs |
|
||||
MiniDumpWithHandleData |
|
||||
MiniDumpWithFullMemoryInfo |
|
||||
MiniDumpWithThreadInfo |
|
||||
MiniDumpWithUnloadedModules);
|
||||
|
||||
BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
|
||||
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
|
||||
|
||||
if (!rv)
|
||||
{
|
||||
LOG_ERROR("Minidump file create FAILED(error " << GetLastError() << ") on path: " << path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Minidump file created on path: " << path);
|
||||
}
|
||||
// Close the file
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Minidump FAILED to create file (error " << GetLastError() << ") on path: " << path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else // ifdef WIN32
|
||||
std::string get_nix_version_display_string()
|
||||
{
|
||||
utsname un;
|
||||
|
||||
if(uname(&un) < 0)
|
||||
return std::string("*nix: failed to get os version");
|
||||
return std::string() + un.sysname + " " + un.version + " " + un.release;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string get_os_version_string()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return get_windows_version_display_string();
|
||||
#else
|
||||
return get_nix_version_display_string();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
std::wstring get_special_folder_path_w(int nfolder, bool iscreate)
|
||||
{
|
||||
wchar_t psz_path[MAX_PATH] = L"";
|
||||
|
||||
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
|
||||
{
|
||||
return psz_path;
|
||||
}
|
||||
|
||||
LOG_ERROR("SHGetSpecialFolderPathW(" << nfolder << ", " << iscreate << ") failed, could not obtain requested path.");
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::string get_special_folder_path_utf8(int nfolder, bool iscreate)
|
||||
{
|
||||
return epee::string_encoding::wstring_to_utf8(get_special_folder_path_w(nfolder, iscreate));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string get_default_data_dir()
|
||||
{
|
||||
//namespace fs = boost::filesystem;
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\CURRENCY_NAME_SHORT
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
|
||||
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
|
||||
// Unix: ~/.CURRENCY_NAME_SHORT
|
||||
std::string config_folder;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
#ifdef _M_X64
|
||||
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
|
||||
#else
|
||||
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
|
||||
#endif
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||
pathRet = "/";
|
||||
else
|
||||
pathRet = pszHome;
|
||||
#ifdef __APPLE__
|
||||
// Mac
|
||||
pathRet += "/Library/Application Support";
|
||||
config_folder = (pathRet + "/" + CURRENCY_NAME_SHORT);
|
||||
#else
|
||||
// Unix
|
||||
config_folder = (pathRet + "/." + CURRENCY_NAME_SHORT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return config_folder;
|
||||
}
|
||||
std::string get_host_computer_name()
|
||||
{
|
||||
char szname[1024] = "";
|
||||
gethostname(szname, sizeof(szname));
|
||||
szname[sizeof(szname)-1] = 0; //just to be sure
|
||||
return szname;
|
||||
}
|
||||
|
||||
|
||||
std::string get_default_user_dir()
|
||||
{
|
||||
//namespace fs = boost::filesystem;
|
||||
// Windows < Vista: C:\Documents and Settings\Username
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
|
||||
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
|
||||
// Unix: ~/.CURRENCY_NAME_SHORT
|
||||
std::string wallets_dir;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
wallets_dir = get_special_folder_path_utf8(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||
pathRet = "/";
|
||||
else
|
||||
pathRet = pszHome;
|
||||
|
||||
wallets_dir = (pathRet + "/" + CURRENCY_NAME_BASE);
|
||||
|
||||
#endif
|
||||
return wallets_dir;
|
||||
}
|
||||
|
||||
std::string get_current_username()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
const char* psz_username = getenv("USERNAME");
|
||||
#else
|
||||
const char* psz_username = getenv("USER");
|
||||
#endif
|
||||
if (psz_username == NULL || strlen(psz_username) == 0)
|
||||
psz_username = "unknown_user";
|
||||
|
||||
return std::string(psz_username);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool create_directories_if_necessary(const std::string& path)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
boost::system::error_code ec;
|
||||
fs::path fs_path = epee::string_encoding::utf8_to_wstring(path);
|
||||
if (fs::is_directory(fs_path, ec))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool res = fs::create_directories(fs_path, ec);
|
||||
if (res)
|
||||
{
|
||||
LOG_PRINT_L2("Created directory: " << path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L2("Can't create directory: " << path << ", err: "<< ec.message());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name)
|
||||
{
|
||||
int code;
|
||||
#if defined(WIN32)
|
||||
// Maximizing chances for success
|
||||
DWORD attributes = ::GetFileAttributes(replaced_name.c_str());
|
||||
if (INVALID_FILE_ATTRIBUTES != attributes)
|
||||
{
|
||||
::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
|
||||
}
|
||||
|
||||
bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
|
||||
code = ok ? 0 : static_cast<int>(::GetLastError());
|
||||
#else
|
||||
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
|
||||
code = ok ? 0 : errno;
|
||||
#endif
|
||||
return std::error_code(code, std::system_category());
|
||||
}
|
||||
|
||||
#define REQUEST_LOG_CHUNK_SIZE_MAX (10 * 1024 * 1024)
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error)
|
||||
{
|
||||
if (size > REQUEST_LOG_CHUNK_SIZE_MAX)
|
||||
{
|
||||
error = std::string("size is exceeding the limit = ") + epee::string_tools::num_to_string_fast(REQUEST_LOG_CHUNK_SIZE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
if (std::ifstream log{ log_filename, std::ifstream::ate | std::ifstream::binary })
|
||||
{
|
||||
uint64_t file_size = log.tellg();
|
||||
|
||||
if (offset >= file_size)
|
||||
{
|
||||
error = "offset is out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + size > file_size)
|
||||
{
|
||||
error = "offset + size if out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
log.seekg(offset);
|
||||
output.resize(size);
|
||||
log.read(&output.front(), size);
|
||||
uint64_t read_bytes = log.gcount();
|
||||
if (read_bytes != size)
|
||||
{
|
||||
error = std::string("read bytes: ") + epee::string_tools::num_to_string_fast(read_bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::pack(output))
|
||||
{
|
||||
error = "zlib pack failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
error = std::string("can't open ") + log_filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t get_log_file_size()
|
||||
{
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
std::ifstream in(log_filename, std::ifstream::ate | std::ifstream::binary);
|
||||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
bool check_remote_client_version(const std::string& client_ver)
|
||||
{
|
||||
std::string v = client_ver.substr(0, client_ver.find('[')); // remove commit id
|
||||
v = v.substr(0, v.rfind('.')); // remove build number
|
||||
|
||||
int v_major = 0, v_minor = 0, v_revision = 0;
|
||||
|
||||
size_t dot_pos = v.find('.');
|
||||
if (dot_pos == std::string::npos || !epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_major))
|
||||
return false;
|
||||
|
||||
v = v.substr(dot_pos + 1);
|
||||
dot_pos = v.find('.');
|
||||
if (!epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_minor))
|
||||
return false;
|
||||
|
||||
if (dot_pos != std::string::npos)
|
||||
{
|
||||
// revision
|
||||
v = v.substr(dot_pos + 1);
|
||||
if (!epee::string_tools::string_to_num_fast(v, v_revision))
|
||||
return false;
|
||||
}
|
||||
|
||||
// got v_major, v_minor, v_revision
|
||||
|
||||
// allow 1.1.x and greater
|
||||
|
||||
if (v_major < 1)
|
||||
return false;
|
||||
|
||||
if (v_major == 1 && v_minor < 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//this code was taken from https://stackoverflow.com/a/8594696/5566653
|
||||
//credits goes to @nijansen: https://stackoverflow.com/users/1056003/nijansen
|
||||
bool copy_dir( boost::filesystem::path const & source, boost::filesystem::path const & destination)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
try
|
||||
{
|
||||
// Check whether the function call is valid
|
||||
if (!fs::exists(source) ||!fs::is_directory(source))
|
||||
{
|
||||
LOG_ERROR("Source directory " << source.string() << " does not exist or is not a directory.");
|
||||
return false;
|
||||
}
|
||||
if (!fs::exists(destination))
|
||||
{
|
||||
if (!fs::create_directory(destination))
|
||||
{
|
||||
LOG_ERROR("Unable to create destination directory" << destination.string());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Create the destination directory
|
||||
}
|
||||
catch (fs::filesystem_error const & e)
|
||||
{
|
||||
LOG_ERROR("Exception: " << e.what());
|
||||
return false;
|
||||
}
|
||||
// Iterate through the source directory
|
||||
for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file)
|
||||
{
|
||||
try
|
||||
{
|
||||
fs::path current(file->path());
|
||||
if (fs::is_directory(current))
|
||||
{
|
||||
// Found directory: Recursion
|
||||
if (!copy_dir(current, destination / current.filename()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found file: Copy
|
||||
fs::copy_file( current, destination / current.filename());
|
||||
}
|
||||
}
|
||||
catch (fs::filesystem_error const & e)
|
||||
{
|
||||
LOG_ERROR("Exception: " << e.what());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "ntp.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <dbghelp.h>
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define BUILD_TYPE "Release"
|
||||
#else
|
||||
#define BUILD_TYPE "Debug"
|
||||
#endif
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::string get_host_computer_name();
|
||||
std::string get_default_data_dir();
|
||||
std::string get_default_user_dir();
|
||||
std::string get_current_username();
|
||||
std::string get_os_version_string();
|
||||
bool copy_dir(boost::filesystem::path const & source, boost::filesystem::path const & destination);
|
||||
bool check_remote_client_version(const std::string& client_ver);
|
||||
|
||||
bool create_directories_if_necessary(const std::string& path);
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
|
||||
|
||||
inline crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot)
|
||||
{
|
||||
std::string s;
|
||||
s.append(reinterpret_cast<const char*>(&pot.peer_id), sizeof(pot.peer_id));
|
||||
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
|
||||
return crypto::cn_fast_hash(s.data(), s.size());
|
||||
}
|
||||
|
||||
inline
|
||||
crypto::public_key get_public_key_from_string(const std::string& str_key)
|
||||
{
|
||||
crypto::public_key k = AUTO_VAL_INIT(k);
|
||||
epee::string_tools::hex_to_pod(str_key, k);
|
||||
return k;
|
||||
}
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error);
|
||||
uint64_t get_log_file_size();
|
||||
|
||||
class signal_handler
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static bool install(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE);
|
||||
if (r)
|
||||
{
|
||||
m_handler = t;
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
signal(SIGINT, posix_handler);
|
||||
signal(SIGTERM, posix_handler);
|
||||
m_handler = t;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void install_fatal(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
// NOTE: Unfortunately, there's no way to handle heap corruption signals/exceptions. More info: https://connect.microsoft.com/VisualStudio/feedback/details/664497/cant-catch-0xc0000374-exception-status-heap-corruption
|
||||
::SetUnhandledExceptionFilter(win_unhandled_exception_handler);
|
||||
#else
|
||||
signal(SIGABRT, posix_fatal_handler);
|
||||
signal(SIGSEGV, posix_fatal_handler);
|
||||
signal(SIGILL, posix_fatal_handler);
|
||||
#endif
|
||||
|
||||
m_fatal_handler = t;
|
||||
}
|
||||
|
||||
static void uninstall_fatal()
|
||||
{
|
||||
#if defined(WIN32)
|
||||
::SetUnhandledExceptionFilter(NULL);
|
||||
#endif
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
signal(SIGILL, SIG_DFL);
|
||||
m_fatal_handler = &noop_fatal_handler;
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
static BOOL WINAPI win_handler(DWORD type)
|
||||
{
|
||||
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
|
||||
{
|
||||
handle_signal();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving...");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
// This code borrowed from http://www.debuginfo.com/articles/effminidumps2.html
|
||||
/************************************************************************/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This function determines whether we need data sections of the given module
|
||||
//
|
||||
|
||||
static bool IsDataSectionNeeded(const WCHAR* pModuleName)
|
||||
{
|
||||
// Check parameters
|
||||
if (pModuleName == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the module name
|
||||
|
||||
WCHAR szFileName[_MAX_FNAME] = L"";
|
||||
|
||||
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
|
||||
// Compare the name with the list of known names and decide
|
||||
// Note: For this to work, the executable name must be "mididump.exe"
|
||||
if (wcsicmp(szFileName, L"mididump") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (wcsicmp(szFileName, L"ntdll") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Complete
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Custom minidump callback
|
||||
//
|
||||
|
||||
static BOOL CALLBACK MyMiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput,
|
||||
PMINIDUMP_CALLBACK_OUTPUT pOutput)
|
||||
{
|
||||
BOOL bRet = FALSE;
|
||||
// Check parameters
|
||||
if (pInput == 0)
|
||||
return FALSE;
|
||||
|
||||
if (pOutput == 0)
|
||||
return FALSE;
|
||||
|
||||
// Process the callbacks
|
||||
switch (pInput->CallbackType)
|
||||
{
|
||||
case IncludeModuleCallback:
|
||||
{
|
||||
// Include the module into the dump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IncludeThreadCallback:
|
||||
{
|
||||
// Include the thread into the dump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ModuleCallback:
|
||||
{
|
||||
// Are data sections available for this module ?
|
||||
|
||||
if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
|
||||
{
|
||||
// Yes, they are, but do we need them?
|
||||
|
||||
if (!IsDataSectionNeeded(pInput->Module.FullPath))
|
||||
{
|
||||
wprintf(L"Excluding module data sections: %s \n", pInput->Module.FullPath);
|
||||
|
||||
pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
|
||||
}
|
||||
}
|
||||
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ThreadCallback:
|
||||
{
|
||||
// Include all thread information into the minidump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ThreadExCallback:
|
||||
{
|
||||
// Include this information
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryCallback:
|
||||
{
|
||||
// We do not include any information here -> return FALSE
|
||||
bRet = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case CancelCallback:
|
||||
break;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
|
||||
}
|
||||
|
||||
static void GenerateCrashDump(EXCEPTION_POINTERS *pep = NULL);
|
||||
|
||||
static LONG WINAPI win_unhandled_exception_handler(_In_ struct _EXCEPTION_POINTERS *ep)
|
||||
{
|
||||
GenerateCrashDump(ep);
|
||||
handle_fatal_signal(ep->ExceptionRecord->ExceptionCode, ep->ExceptionRecord->ExceptionAddress);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
#else
|
||||
static void posix_handler(int /*type*/)
|
||||
{
|
||||
handle_signal();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void posix_fatal_handler(int sig_number)
|
||||
{
|
||||
handle_fatal_signal(sig_number, 0);
|
||||
}
|
||||
|
||||
static void noop_fatal_handler(int, void*) {}
|
||||
|
||||
static void handle_signal()
|
||||
{
|
||||
static epee::static_helpers::wrapper<std::mutex> m_mutex;
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_handler();
|
||||
}
|
||||
|
||||
static void handle_fatal_signal(int sig_number, void* address)
|
||||
{
|
||||
static epee::static_helpers::wrapper<std::mutex> m_mutex_fatal;
|
||||
std::unique_lock<std::mutex> lock(m_mutex_fatal);
|
||||
m_fatal_handler(sig_number, address);
|
||||
uninstall_fatal();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::function<void(void)> m_handler;
|
||||
static std::function<void(int, void*)> m_fatal_handler;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
template<typename T>
|
||||
size_t get_varint_packed_size(T v)
|
||||
{
|
||||
if(v <= 127)
|
||||
return 1;
|
||||
else if(v <= 16383)
|
||||
return 2;
|
||||
else if(v <= 2097151)
|
||||
return 3;
|
||||
else if(v <= 268435455)
|
||||
return 4;
|
||||
else if(v <= 34359738367)
|
||||
return 5;
|
||||
else if(v <= 4398046511103)
|
||||
return 6;
|
||||
else if(v <= 562949953421311)
|
||||
return 7;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
template<typename OutputIt, typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, void>::type
|
||||
write_varint(OutputIt &&dest, T i) {
|
||||
while (i >= 0x80) {
|
||||
*dest++ = (static_cast<char>(i) & 0x7f) | 0x80;
|
||||
i >>= 7;
|
||||
}
|
||||
*dest++ = static_cast<char>(i);
|
||||
}
|
||||
|
||||
template<typename t_type>
|
||||
std::string get_varint_data(const t_type& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
write_varint(std::ostreambuf_iterator<char>(ss), v);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<int bits, typename InputIt, typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value && 0 <= bits && bits <= std::numeric_limits<T>::digits, int>::type
|
||||
read_varint(InputIt &&first, InputIt &&last, T &i) {
|
||||
int read = 0;
|
||||
i = 0;
|
||||
for (int shift = 0;; shift += 7) {
|
||||
if (first == last) {
|
||||
return read; // End of input.
|
||||
}
|
||||
unsigned char byte = *first++;
|
||||
++read;
|
||||
if (shift + 7 >= bits && byte >= 1 << (bits - shift)) {
|
||||
return -1; // Overflow.
|
||||
}
|
||||
if (byte == 0 && shift != 0) {
|
||||
return -2; // Non-canonical representation.
|
||||
}
|
||||
i |= static_cast<T>(byte & 0x7f) << shift;
|
||||
if ((byte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
template<typename InputIt, typename T>
|
||||
int read_varint(InputIt &&first, InputIt &&last, T &i) {
|
||||
return read_varint<std::numeric_limits<T>::digits, InputIt, T>(std::move(first), std::move(last), i);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
message("excluded db support for IOS build")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
message("DB ENGINE: lmdb")
|
||||
add_subdirectory(liblmdb)
|
||||
if(MSVC)
|
||||
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
|
||||
else()
|
||||
# Warnings as used by LMDB itself (LMDB_0.9.23)
|
||||
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
|
||||
endif()
|
||||
if(NOT DISABLE_MDBX)
|
||||
message("DB ENGINE: mdbx")
|
||||
add_subdirectory(libmdbx)
|
||||
endif()
|
||||
23
src/contrib/db/liblmdb/.gitignore
vendored
23
src/contrib/db/liblmdb/.gitignore
vendored
|
|
@ -1,23 +0,0 @@
|
|||
mtest
|
||||
mtest[23456]
|
||||
testdb
|
||||
mdb_copy
|
||||
mdb_stat
|
||||
mdb_dump
|
||||
mdb_load
|
||||
*.lo
|
||||
*.[ao]
|
||||
*.so
|
||||
*.exe
|
||||
*[~#]
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
*.gcov
|
||||
*.gcda
|
||||
*.gcno
|
||||
core
|
||||
core.*
|
||||
valgrind.*
|
||||
man/
|
||||
html/
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
LMDB 0.9 Change Log
|
||||
|
||||
LMDB 0.9.18 Release Engineering
|
||||
Fix robust mutex detection on glibc 2.10-11 (ITS#8330)
|
||||
Check for utf8_to_utf16 failures (ITS#7992)
|
||||
Catch strdup failure in mdb_dbi_open
|
||||
Build
|
||||
Additional makefile var tweaks (ITS#8169)
|
||||
Documentation
|
||||
Add Getting Started page
|
||||
|
||||
|
||||
LMDB 0.9.17 Release (2015/11/30)
|
||||
Fix ITS#7377 catch calloc failure
|
||||
Fix ITS#8237 regression from ITS#7589
|
||||
Fix ITS#8238 page_split for DUPFIXED pages
|
||||
Fix ITS#8221 MDB_PAGE_FULL on delete/rebalance
|
||||
Fix ITS#8258 rebalance/split assert
|
||||
Fix ITS#8263 cursor_put cursor tracking
|
||||
Fix ITS#8264 cursor_del cursor tracking
|
||||
Fix ITS#8310 cursor_del cursor tracking
|
||||
Fix ITS#8299 mdb_del cursor tracking
|
||||
Fix ITS#8300 mdb_del cursor tracking
|
||||
Fix ITS#8304 mdb_del cursor tracking
|
||||
Fix ITS#7771 fakepage cursor tracking
|
||||
Fix ITS#7789 ensure mapsize >= pages in use
|
||||
Fix ITS#7971 mdb_txn_renew0() new reader slots
|
||||
Fix ITS#7969 use __sync_synchronize on non-x86
|
||||
Fix ITS#8311 page_split from update_key
|
||||
Fix ITS#8312 loose pages in nested txn
|
||||
Fix ITS#8313 mdb_rebalance dummy cursor
|
||||
Fix ITS#8315 dirty_room in nested txn
|
||||
Fix ITS#8323 dirty_list in nested txn
|
||||
Fix ITS#8316 page_merge cursor tracking
|
||||
Fix ITS#8321 cursor tracking
|
||||
Fix ITS#8319 mdb_load error messages
|
||||
Fix ITS#8320 mdb_load plaintext input
|
||||
Added mdb_txn_id() (ITS#7994)
|
||||
Added robust mutex support
|
||||
Miscellaneous cleanup/simplification
|
||||
Build
|
||||
Create install dirs if needed (ITS#8256)
|
||||
Fix ThreadProc decl on Win32/MSVC (ITS#8270)
|
||||
Added ssize_t typedef for MSVC (ITS#8067)
|
||||
Use ANSI apis on Windows (ITS#8069)
|
||||
Use O_SYNC if O_DSYNC,MDB_DSYNC are not defined (ITS#7209)
|
||||
Allow passing AR to make (ITS#8168)
|
||||
Allow passing mandir to make install (ITS#8169)
|
||||
|
||||
LMDB 0.9.16 Release (2015/08/14)
|
||||
Fix cursor EOF bug (ITS#8190)
|
||||
Fix handling of subDB records (ITS#8181)
|
||||
Fix mdb_midl_shrink() usage (ITS#8200)
|
||||
|
||||
LMDB 0.9.15 Release (2015/06/19)
|
||||
Fix txn init (ITS#7961,#7987)
|
||||
Fix MDB_PREV_DUP (ITS#7955,#7671)
|
||||
Fix compact of empty env (ITS#7956)
|
||||
Fix mdb_copy file mode
|
||||
Fix mdb_env_close() after failed mdb_env_open()
|
||||
Fix mdb_rebalance collapsing root (ITS#8062)
|
||||
Fix mdb_load with large values (ITS#8066)
|
||||
Fix to retry writes on EINTR (ITS#8106)
|
||||
Fix mdb_cursor_del on empty DB (ITS#8109)
|
||||
Fix MDB_INTEGERDUP key compare (ITS#8117)
|
||||
Fix error handling (ITS#7959,#8157,etc.)
|
||||
Fix race conditions (ITS#7969,7970)
|
||||
Added workaround for fdatasync bug in ext3fs
|
||||
Build
|
||||
Don't use -fPIC for static lib
|
||||
Update .gitignore (ITS#7952,#7953)
|
||||
Cleanup for "make test" (ITS#7841), "make clean", mtest*.c
|
||||
Misc. Android/Windows cleanup
|
||||
Documentation
|
||||
Fix MDB_APPEND doc
|
||||
Fix MDB_MAXKEYSIZE doc (ITS#8156)
|
||||
Fix mdb_cursor_put,mdb_cursor_del EACCES description
|
||||
Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021)
|
||||
Clarify MDB_WRITEMAP doc (ITS#8021)
|
||||
Clarify mdb_env_open doc
|
||||
Clarify mdb_dbi_open doc
|
||||
|
||||
LMDB 0.9.14 Release (2014/09/20)
|
||||
Fix to support 64K page size (ITS#7713)
|
||||
Fix to persist decreased as well as increased mapsizes (ITS#7789)
|
||||
Fix cursor bug when deleting last node of a DUPSORT key
|
||||
Fix mdb_env_info to return FIXEDMAP address
|
||||
Fix ambiguous error code from writing to closed DBI (ITS#7825)
|
||||
Fix mdb_copy copying past end of file (ITS#7886)
|
||||
Fix cursor bugs from page_merge/rebalance
|
||||
Fix to dirty fewer pages in deletes (mdb_page_loose())
|
||||
Fix mdb_dbi_open creating subDBs (ITS#7917)
|
||||
Fix mdb_cursor_get(_DUP) with single value (ITS#7913)
|
||||
Fix Windows compat issues in mtests (ITS#7879)
|
||||
Add compacting variant of mdb_copy
|
||||
Add BigEndian integer key compare code
|
||||
Add mdb_dump/mdb_load utilities
|
||||
|
||||
LMDB 0.9.13 Release (2014/06/18)
|
||||
Fix mdb_page_alloc unlimited overflow page search
|
||||
Documentation
|
||||
Re-fix MDB_CURRENT doc (ITS#7793)
|
||||
Fix MDB_GET_MULTIPLE/MDB_NEXT_MULTIPLE doc
|
||||
|
||||
LMDB 0.9.12 Release (2014/06/13)
|
||||
Fix MDB_GET_BOTH regression (ITS#7875,#7681)
|
||||
Fix MDB_MULTIPLE writing multiple keys (ITS#7834)
|
||||
Fix mdb_rebalance (ITS#7829)
|
||||
Fix mdb_page_split (ITS#7815)
|
||||
Fix md_entries count (ITS#7861,#7828,#7793)
|
||||
Fix MDB_CURRENT (ITS#7793)
|
||||
Fix possible crash on Windows DLL detach
|
||||
Misc code cleanup
|
||||
Documentation
|
||||
mdb_cursor_put: cursor moves on error (ITS#7771)
|
||||
|
||||
|
||||
LMDB 0.9.11 Release (2014/01/15)
|
||||
Add mdb_env_set_assert() (ITS#7775)
|
||||
Fix: invalidate txn on page allocation errors (ITS#7377)
|
||||
Fix xcursor tracking in mdb_cursor_del0() (ITS#7771)
|
||||
Fix corruption from deletes (ITS#7756)
|
||||
Fix Windows/MSVC build issues
|
||||
Raise safe limit of max MDB_MAXKEYSIZE
|
||||
Misc code cleanup
|
||||
Documentation
|
||||
Remove spurious note about non-overlapping flags (ITS#7665)
|
||||
|
||||
LMDB 0.9.10 Release (2013/11/12)
|
||||
Add MDB_NOMEMINIT option
|
||||
Fix mdb_page_split() again (ITS#7589)
|
||||
Fix MDB_NORDAHEAD definition (ITS#7734)
|
||||
Fix mdb_cursor_del() positioning (ITS#7733)
|
||||
Partial fix for larger page sizes (ITS#7713)
|
||||
Fix Windows64/MSVC build issues
|
||||
|
||||
LMDB 0.9.9 Release (2013/10/24)
|
||||
Add mdb_env_get_fd()
|
||||
Add MDB_NORDAHEAD option
|
||||
Add MDB_NOLOCK option
|
||||
Avoid wasting space in mdb_page_split() (ITS#7589)
|
||||
Fix mdb_page_merge() cursor fixup (ITS#7722)
|
||||
Fix mdb_cursor_del() on last delete (ITS#7718)
|
||||
Fix adding WRITEMAP on existing env (ITS#7715)
|
||||
Fix nested txns (ITS#7515)
|
||||
Fix mdb_env_copy() O_DIRECT bug (ITS#7682)
|
||||
Fix mdb_cursor_set(SET_RANGE) return code (ITS#7681)
|
||||
Fix mdb_rebalance() cursor fixup (ITS#7701)
|
||||
Misc code cleanup
|
||||
Documentation
|
||||
Note that by default, readers need write access
|
||||
|
||||
|
||||
LMDB 0.9.8 Release (2013/09/09)
|
||||
Allow mdb_env_set_mapsize() on an open environment
|
||||
Fix mdb_dbi_flags() (ITS#7672)
|
||||
Fix mdb_page_unspill() in nested txns
|
||||
Fix mdb_cursor_get(CURRENT|NEXT) after a delete
|
||||
Fix mdb_cursor_get(DUP) to always return key (ITS#7671)
|
||||
Fix mdb_cursor_del() to always advance to next item (ITS#7670)
|
||||
Fix mdb_cursor_set(SET_RANGE) for tree with single page (ITS#7681)
|
||||
Fix mdb_env_copy() retry open if O_DIRECT fails (ITS#7682)
|
||||
Tweak mdb_page_spill() to be less aggressive
|
||||
Documentation
|
||||
Update caveats since mdb_reader_check() added in 0.9.7
|
||||
|
||||
LMDB 0.9.7 Release (2013/08/17)
|
||||
Don't leave stale lockfile on failed RDONLY open (ITS#7664)
|
||||
Fix mdb_page_split() ref beyond cursor depth
|
||||
Fix read txn data race (ITS#7635)
|
||||
Fix mdb_rebalance (ITS#7536, #7538)
|
||||
Fix mdb_drop() (ITS#7561)
|
||||
Misc DEBUG macro fixes
|
||||
Add MDB_NOTLS envflag
|
||||
Add mdb_env_copyfd()
|
||||
Add mdb_txn_env() (ITS#7660)
|
||||
Add mdb_dbi_flags() (ITS#7661)
|
||||
Add mdb_env_get_maxkeysize()
|
||||
Add mdb_env_reader_list()/mdb_env_reader_check()
|
||||
Add mdb_page_spill/unspill, remove hard txn size limit
|
||||
Use shorter names for semaphores (ITS#7615)
|
||||
Build
|
||||
Fix install target (ITS#7656)
|
||||
Documentation
|
||||
Misc updates for cursors, DB handles, data lifetime
|
||||
|
||||
LMDB 0.9.6 Release (2013/02/25)
|
||||
Many fixes/enhancements
|
||||
|
||||
LMDB 0.9.5 Release (2012/11/30)
|
||||
Renamed from libmdb to liblmdb
|
||||
Many fixes/enhancements
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
set (lmdb_sources mdb.c midl.c)
|
||||
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-missing-braces -Wno-aggregate-return -Wno-discarded-qualifiers -Wno-unused-but-set-variable -Wno-implicit-fallthrough -Wno-maybe-uninitialized ")
|
||||
endif()
|
||||
if(FREEBSD)
|
||||
add_definitions(-DMDB_DSYNC=O_SYNC)
|
||||
endif()
|
||||
|
||||
add_library(lmdb ${lmdb_sources})
|
||||
|
||||
target_link_libraries(lmdb PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(lmdb ntdll)
|
||||
endif()
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted only as authorized by the OpenLDAP
|
||||
Public License.
|
||||
|
||||
A copy of this license is available in the file LICENSE in the
|
||||
top-level directory of the distribution or, alternatively, at
|
||||
<http://www.OpenLDAP.org/license.html>.
|
||||
|
||||
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
|
||||
|
||||
Individual files and/or contributed packages may be copyright by
|
||||
other parties and/or subject to additional restrictions.
|
||||
|
||||
This work also contains materials derived from public sources.
|
||||
|
||||
Additional information about OpenLDAP can be obtained at
|
||||
<http://www.openldap.org/>.
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,47 +0,0 @@
|
|||
The OpenLDAP Public License
|
||||
Version 2.8, 17 August 2003
|
||||
|
||||
Redistribution and use of this software and associated documentation
|
||||
("Software"), with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions in source form must retain copyright statements
|
||||
and notices,
|
||||
|
||||
2. Redistributions in binary form must reproduce applicable copyright
|
||||
statements and notices, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution, and
|
||||
|
||||
3. Redistributions must contain a verbatim copy of this document.
|
||||
|
||||
The OpenLDAP Foundation may revise this license from time to time.
|
||||
Each revision is distinguished by a version number. You may use
|
||||
this Software under terms of this license revision or under the
|
||||
terms of any subsequent revision of the license.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
|
||||
CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
|
||||
OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The names of the authors and copyright holders must not be used in
|
||||
advertising or otherwise to promote the sale, use or other dealing
|
||||
in this Software without specific, written prior permission. Title
|
||||
to copyright in this Software shall at all times remain with copyright
|
||||
holders.
|
||||
|
||||
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
|
||||
|
||||
Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
|
||||
California, USA. All Rights Reserved. Permission to copy and
|
||||
distribute verbatim copies of this document is granted.
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
# Makefile for liblmdb (Lightning memory-mapped database library).
|
||||
|
||||
########################################################################
|
||||
# Configuration. The compiler options must enable threaded compilation.
|
||||
#
|
||||
# Preprocessor macros (for CPPFLAGS) of interest...
|
||||
# Note that the defaults should already be correct for most
|
||||
# platforms; you should not need to change any of these.
|
||||
# Read their descriptions in mdb.c if you do:
|
||||
#
|
||||
# - MDB_USE_POSIX_MUTEX, MDB_USE_POSIX_SEM, MDB_USE_SYSV_SEM
|
||||
# - MDB_DSYNC
|
||||
# - MDB_FDATASYNC
|
||||
# - MDB_FDATASYNC_WORKS
|
||||
# - MDB_USE_PWRITEV
|
||||
# - MDB_USE_ROBUST
|
||||
#
|
||||
# There may be other macros in mdb.c of interest. You should
|
||||
# read mdb.c before changing any of them.
|
||||
#
|
||||
CC = gcc
|
||||
AR = ar
|
||||
W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized
|
||||
THREADS = -pthread
|
||||
OPT = -O2 -g
|
||||
CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS)
|
||||
LDLIBS = # -lntdll # Windows needs ntdll
|
||||
SOLIBS = # -lntdll
|
||||
prefix = /usr/local
|
||||
exec_prefix = $(prefix)
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
includedir = $(prefix)/include
|
||||
datarootdir = $(prefix)/share
|
||||
mandir = $(datarootdir)/man
|
||||
|
||||
########################################################################
|
||||
|
||||
IHDRS = lmdb.h
|
||||
ILIBS = liblmdb.a liblmdb.so
|
||||
IPROGS = mdb_stat mdb_copy mdb_dump mdb_load
|
||||
IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
|
||||
PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5
|
||||
all: $(ILIBS) $(PROGS)
|
||||
|
||||
install: $(ILIBS) $(IPROGS) $(IHDRS)
|
||||
mkdir -p $(DESTDIR)$(bindir)
|
||||
mkdir -p $(DESTDIR)$(libdir)
|
||||
mkdir -p $(DESTDIR)$(includedir)
|
||||
mkdir -p $(DESTDIR)$(mandir)/man1
|
||||
for f in $(IPROGS); do cp $$f $(DESTDIR)$(bindir); done
|
||||
for f in $(ILIBS); do cp $$f $(DESTDIR)$(libdir); done
|
||||
for f in $(IHDRS); do cp $$f $(DESTDIR)$(includedir); done
|
||||
for f in $(IDOCS); do cp $$f $(DESTDIR)$(mandir)/man1; done
|
||||
|
||||
clean:
|
||||
rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb
|
||||
|
||||
test: all
|
||||
rm -rf testdb && mkdir testdb
|
||||
./mtest && ./mdb_stat testdb
|
||||
|
||||
liblmdb.a: mdb.o midl.o
|
||||
$(AR) rs $@ mdb.o midl.o
|
||||
|
||||
liblmdb.so: mdb.lo midl.lo
|
||||
# $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS)
|
||||
$(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS)
|
||||
|
||||
mdb_stat: mdb_stat.o liblmdb.a
|
||||
mdb_copy: mdb_copy.o liblmdb.a
|
||||
mdb_dump: mdb_dump.o liblmdb.a
|
||||
mdb_load: mdb_load.o liblmdb.a
|
||||
mtest: mtest.o liblmdb.a
|
||||
mtest2: mtest2.o liblmdb.a
|
||||
mtest3: mtest3.o liblmdb.a
|
||||
mtest4: mtest4.o liblmdb.a
|
||||
mtest5: mtest5.o liblmdb.a
|
||||
mtest6: mtest6.o liblmdb.a
|
||||
|
||||
mdb.o: mdb.c lmdb.h midl.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c
|
||||
|
||||
midl.o: midl.c midl.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c
|
||||
|
||||
mdb.lo: mdb.c lmdb.h midl.h
|
||||
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@
|
||||
|
||||
midl.lo: midl.c midl.h
|
||||
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@
|
||||
|
||||
%: %.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
%.o: %.c lmdb.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
|
||||
|
||||
COV_FLAGS=-fprofile-arcs -ftest-coverage
|
||||
COV_OBJS=xmdb.o xmidl.o
|
||||
|
||||
coverage: xmtest
|
||||
for i in mtest*.c [0-9]*.c; do j=`basename \$$i .c`; $(MAKE) $$j.o; \
|
||||
gcc -o x$$j $$j.o $(COV_OBJS) -pthread $(COV_FLAGS); \
|
||||
rm -rf testdb; mkdir testdb; ./x$$j; done
|
||||
gcov xmdb.c
|
||||
gcov xmidl.c
|
||||
|
||||
xmtest: mtest.o xmdb.o xmidl.o
|
||||
gcc -o xmtest mtest.o xmdb.o xmidl.o -pthread $(COV_FLAGS)
|
||||
|
||||
xmdb.o: mdb.c lmdb.h midl.h
|
||||
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c mdb.c -o $@
|
||||
|
||||
xmidl.o: midl.c midl.h
|
||||
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c midl.c -o $@
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
/** @page starting Getting Started
|
||||
|
||||
LMDB is compact, fast, powerful, and robust and implements a simplified
|
||||
variant of the BerkeleyDB (BDB) API. (BDB is also very powerful, and verbosely
|
||||
documented in its own right.) After reading this page, the main
|
||||
\ref mdb documentation should make sense. Thanks to Bert Hubert
|
||||
for creating the
|
||||
<a href="https://github.com/ahupowerdns/ahutils/blob/master/lmdb-semantics.md">
|
||||
initial version</a> of this writeup.
|
||||
|
||||
Everything starts with an environment, created by #mdb_env_create().
|
||||
Once created, this environment must also be opened with #mdb_env_open().
|
||||
|
||||
#mdb_env_open() gets passed a name which is interpreted as a directory
|
||||
path. Note that this directory must exist already, it is not created
|
||||
for you. Within that directory, a lock file and a storage file will be
|
||||
generated. If you don't want to use a directory, you can pass the
|
||||
#MDB_NOSUBDIR option, in which case the path you provided is used
|
||||
directly as the data file, and another file with a "-lock" suffix
|
||||
added will be used for the lock file.
|
||||
|
||||
Once the environment is open, a transaction can be created within it
|
||||
using #mdb_txn_begin(). Transactions may be read-write or read-only,
|
||||
and read-write transactions may be nested. A transaction must only
|
||||
be used by one thread at a time. Transactions are always required,
|
||||
even for read-only access. The transaction provides a consistent
|
||||
view of the data.
|
||||
|
||||
Once a transaction has been created, a database can be opened within it
|
||||
using #mdb_dbi_open(). If only one database will ever be used in the
|
||||
environment, a NULL can be passed as the database name. For named
|
||||
databases, the #MDB_CREATE flag must be used to create the database
|
||||
if it doesn't already exist. Also, #mdb_env_set_maxdbs() must be
|
||||
called after #mdb_env_create() and before #mdb_env_open() to set the
|
||||
maximum number of named databases you want to support.
|
||||
|
||||
Note: a single transaction can open multiple databases. Generally
|
||||
databases should only be opened once, by the first transaction in
|
||||
the process. After the first transaction completes, the database
|
||||
handles can freely be used by all subsequent transactions.
|
||||
|
||||
Within a transaction, #mdb_get() and #mdb_put() can store single
|
||||
key/value pairs if that is all you need to do (but see \ref Cursors
|
||||
below if you want to do more).
|
||||
|
||||
A key/value pair is expressed as two #MDB_val structures. This struct
|
||||
has two fields, \c mv_size and \c mv_data. The data is a \c void pointer to
|
||||
an array of \c mv_size bytes.
|
||||
|
||||
Because LMDB is very efficient (and usually zero-copy), the data returned
|
||||
in an #MDB_val structure may be memory-mapped straight from disk. In
|
||||
other words <b>look but do not touch</b> (or free() for that matter).
|
||||
Once a transaction is closed, the values can no longer be used, so
|
||||
make a copy if you need to keep them after that.
|
||||
|
||||
@section Cursors Cursors
|
||||
|
||||
To do more powerful things, we must use a cursor.
|
||||
|
||||
Within the transaction, a cursor can be created with #mdb_cursor_open().
|
||||
With this cursor we can store/retrieve/delete (multiple) values using
|
||||
#mdb_cursor_get(), #mdb_cursor_put(), and #mdb_cursor_del().
|
||||
|
||||
#mdb_cursor_get() positions itself depending on the cursor operation
|
||||
requested, and for some operations, on the supplied key. For example,
|
||||
to list all key/value pairs in a database, use operation #MDB_FIRST for
|
||||
the first call to #mdb_cursor_get(), and #MDB_NEXT on subsequent calls,
|
||||
until the end is hit.
|
||||
|
||||
To retrieve all keys starting from a specified key value, use #MDB_SET.
|
||||
For more cursor operations, see the \ref mdb docs.
|
||||
|
||||
When using #mdb_cursor_put(), either the function will position the
|
||||
cursor for you based on the \b key, or you can use operation
|
||||
#MDB_CURRENT to use the current position of the cursor. Note that
|
||||
\b key must then match the current position's key.
|
||||
|
||||
@subsection summary Summarizing the Opening
|
||||
|
||||
So we have a cursor in a transaction which opened a database in an
|
||||
environment which is opened from a filesystem after it was
|
||||
separately created.
|
||||
|
||||
Or, we create an environment, open it from a filesystem, create a
|
||||
transaction within it, open a database within that transaction,
|
||||
and create a cursor within all of the above.
|
||||
|
||||
Got it?
|
||||
|
||||
@section thrproc Threads and Processes
|
||||
|
||||
LMDB uses POSIX locks on files, and these locks have issues if one
|
||||
process opens a file multiple times. Because of this, do not
|
||||
#mdb_env_open() a file multiple times from a single process. Instead,
|
||||
share the LMDB environment that has opened the file across all threads.
|
||||
Otherwise, if a single process opens the same environment multiple times,
|
||||
closing it once will remove all the locks held on it, and the other
|
||||
instances will be vulnerable to corruption from other processes.
|
||||
|
||||
Also note that a transaction is tied to one thread by default using
|
||||
Thread Local Storage. If you want to pass read-only transactions across
|
||||
threads, you can use the #MDB_NOTLS option on the environment.
|
||||
|
||||
@section txns Transactions, Rollbacks, etc.
|
||||
|
||||
To actually get anything done, a transaction must be committed using
|
||||
#mdb_txn_commit(). Alternatively, all of a transaction's operations
|
||||
can be discarded using #mdb_txn_abort(). In a read-only transaction,
|
||||
any cursors will \b not automatically be freed. In a read-write
|
||||
transaction, all cursors will be freed and must not be used again.
|
||||
|
||||
For read-only transactions, obviously there is nothing to commit to
|
||||
storage. The transaction still must eventually be aborted to close
|
||||
any database handle(s) opened in it, or committed to keep the
|
||||
database handles around for reuse in new transactions.
|
||||
|
||||
In addition, as long as a transaction is open, a consistent view of
|
||||
the database is kept alive, which requires storage. A read-only
|
||||
transaction that no longer requires this consistent view should
|
||||
be terminated (committed or aborted) when the view is no longer
|
||||
needed (but see below for an optimization).
|
||||
|
||||
There can be multiple simultaneously active read-only transactions
|
||||
but only one that can write. Once a single read-write transaction
|
||||
is opened, all further attempts to begin one will block until the
|
||||
first one is committed or aborted. This has no effect on read-only
|
||||
transactions, however, and they may continue to be opened at any time.
|
||||
|
||||
@section dupkeys Duplicate Keys
|
||||
|
||||
#mdb_get() and #mdb_put() respectively have no and only some support
|
||||
for multiple key/value pairs with identical keys. If there are multiple
|
||||
values for a key, #mdb_get() will only return the first value.
|
||||
|
||||
When multiple values for one key are required, pass the #MDB_DUPSORT
|
||||
flag to #mdb_dbi_open(). In an #MDB_DUPSORT database, by default
|
||||
#mdb_put() will not replace the value for a key if the key existed
|
||||
already. Instead it will add the new value to the key. In addition,
|
||||
#mdb_del() will pay attention to the value field too, allowing for
|
||||
specific values of a key to be deleted.
|
||||
|
||||
Finally, additional cursor operations become available for
|
||||
traversing through and retrieving duplicate values.
|
||||
|
||||
@section optim Some Optimization
|
||||
|
||||
If you frequently begin and abort read-only transactions, as an
|
||||
optimization, it is possible to only reset and renew a transaction.
|
||||
|
||||
#mdb_txn_reset() releases any old copies of data kept around for
|
||||
a read-only transaction. To reuse this reset transaction, call
|
||||
#mdb_txn_renew() on it. Any cursors in this transaction must also
|
||||
be renewed using #mdb_cursor_renew().
|
||||
|
||||
Note that #mdb_txn_reset() is similar to #mdb_txn_abort() and will
|
||||
close any databases you opened within the transaction.
|
||||
|
||||
To permanently free a transaction, reset or not, use #mdb_txn_abort().
|
||||
|
||||
@section cleanup Cleaning Up
|
||||
|
||||
For read-only transactions, any cursors created within it must
|
||||
be closed using #mdb_cursor_close().
|
||||
|
||||
It is very rarely necessary to close a database handle, and in
|
||||
general they should just be left open.
|
||||
|
||||
@section onward The Full API
|
||||
|
||||
The full \ref mdb documentation lists further details, like how to:
|
||||
|
||||
\li size a database (the default limits are intentionally small)
|
||||
\li drop and clean a database
|
||||
\li detect and report errors
|
||||
\li optimize (bulk) loading speed
|
||||
\li (temporarily) reduce robustness to gain even more speed
|
||||
\li gather statistics about the database
|
||||
\li define custom sort orders
|
||||
|
||||
*/
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,60 +0,0 @@
|
|||
.TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_copy \- LMDB environment copy tool
|
||||
.SH SYNOPSIS
|
||||
.B mdb_copy
|
||||
[\c
|
||||
.BR \-V ]
|
||||
[\c
|
||||
.BR \-c ]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
.B srcpath
|
||||
[\c
|
||||
.BR dstpath ]
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B mdb_copy
|
||||
utility copies an LMDB environment. The environment can
|
||||
be copied regardless of whether it is currently in use.
|
||||
No lockfile is created, since it gets recreated at need.
|
||||
|
||||
If
|
||||
.I dstpath
|
||||
is specified it must be the path of an empty directory
|
||||
for storing the backup. Otherwise, the backup will be
|
||||
written to stdout.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-V
|
||||
Write the library version number to the standard output, and exit.
|
||||
.TP
|
||||
.BR \-c
|
||||
Compact while copying. Only current data pages will be copied; freed
|
||||
or unused pages will be omitted from the copy. This option will
|
||||
slow down the backup process as it is more CPU-intensive.
|
||||
.TP
|
||||
.BR \-n
|
||||
Open LDMB environment(s) which do not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
Errors result in a non-zero exit status and
|
||||
a diagnostic message being written to standard error.
|
||||
.SH CAVEATS
|
||||
This utility can trigger significant file size growth if run
|
||||
in parallel with write transactions, because pages which they
|
||||
free during copying cannot be reused until the copy is done.
|
||||
.SH "SEE ALSO"
|
||||
.BR mdb_stat (1)
|
||||
.SH AUTHOR
|
||||
Howard Chu of Symas Corporation <http://www.symas.com>
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/* mdb_copy.c - memory-mapped database backup tool */
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define MDB_STDOUT GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
#else
|
||||
#define MDB_STDOUT 1
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
static void
|
||||
sighandle(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int rc;
|
||||
MDB_env *env;
|
||||
const char *progname = argv[0], *act;
|
||||
unsigned flags = MDB_RDONLY;
|
||||
unsigned cpflags = 0;
|
||||
|
||||
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
|
||||
if (argv[1][1] == 'n' && argv[1][2] == '\0')
|
||||
flags |= MDB_NOSUBDIR;
|
||||
else if (argv[1][1] == 'v' && argv[1][2] == '\0')
|
||||
flags |= MDB_PREVSNAPSHOT;
|
||||
else if (argv[1][1] == 'c' && argv[1][2] == '\0')
|
||||
cpflags |= MDB_CP_COMPACT;
|
||||
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
|
||||
printf("%s\n", MDB_VERSION_STRING);
|
||||
exit(0);
|
||||
} else
|
||||
argc = 0;
|
||||
}
|
||||
|
||||
if (argc<2 || argc>3) {
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] [-v] srcpath [dstpath]\n", progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef SIGPIPE
|
||||
signal(SIGPIPE, sighandle);
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
signal(SIGHUP, sighandle);
|
||||
#endif
|
||||
signal(SIGINT, sighandle);
|
||||
signal(SIGTERM, sighandle);
|
||||
|
||||
act = "opening environment";
|
||||
rc = mdb_env_create(&env);
|
||||
if (rc == MDB_SUCCESS) {
|
||||
rc = mdb_env_open(env, argv[1], flags, 0600);
|
||||
}
|
||||
if (rc == MDB_SUCCESS) {
|
||||
act = "copying";
|
||||
if (argc == 2)
|
||||
rc = mdb_env_copyfd2(env, MDB_STDOUT, cpflags);
|
||||
else
|
||||
rc = mdb_env_copy2(env, argv[2], cpflags);
|
||||
}
|
||||
if (rc)
|
||||
fprintf(stderr, "%s: %s failed, error %d (%s)\n",
|
||||
progname, act, rc, mdb_strerror(rc));
|
||||
mdb_env_close(env);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
.TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_dump \- LMDB environment export tool
|
||||
.SH SYNOPSIS
|
||||
.B mdb_dump
|
||||
[\c
|
||||
.BR \-V ]
|
||||
[\c
|
||||
.BI \-f \ file\fR]
|
||||
[\c
|
||||
.BR \-l ]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-p ]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
.BI \-s \ subdb\fR]
|
||||
.BR \ envpath
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B mdb_dump
|
||||
utility reads a database and writes its contents to the
|
||||
standard output using a portable flat-text format
|
||||
understood by the
|
||||
.BR mdb_load (1)
|
||||
utility.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-V
|
||||
Write the library version number to the standard output, and exit.
|
||||
.TP
|
||||
.BR \-f \ file
|
||||
Write to the specified file instead of to the standard output.
|
||||
.TP
|
||||
.BR \-l
|
||||
List the databases stored in the environment. Just the
|
||||
names will be listed, no data will be output.
|
||||
.TP
|
||||
.BR \-n
|
||||
Dump an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-p
|
||||
If characters in either the key or data items are printing characters (as
|
||||
defined by isprint(3)), output them directly. This option permits users to
|
||||
use standard text editors and tools to modify the contents of databases.
|
||||
|
||||
Note: different systems may have different notions about what characters
|
||||
are considered printing characters, and databases dumped in this manner may
|
||||
be less portable to external systems.
|
||||
.TP
|
||||
.BR \-a
|
||||
Dump all of the subdatabases in the environment.
|
||||
.TP
|
||||
.BR \-s \ subdb
|
||||
Dump a specific subdatabase. If no database is specified, only the main database is dumped.
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
Errors result in a non-zero exit status and
|
||||
a diagnostic message being written to standard error.
|
||||
|
||||
Dumping and reloading databases that use user-defined comparison functions
|
||||
will result in new databases that use the default comparison functions.
|
||||
\fBIn this case it is quite likely that the reloaded database will be
|
||||
damaged beyond repair permitting neither record storage nor retrieval.\fP
|
||||
|
||||
The only available workaround is to modify the source for the
|
||||
.BR mdb_load (1)
|
||||
utility to load the database using the correct comparison functions.
|
||||
.SH "SEE ALSO"
|
||||
.BR mdb_load (1)
|
||||
.SH AUTHOR
|
||||
Howard Chu of Symas Corporation <http://www.symas.com>
|
||||
|
|
@ -1,330 +0,0 @@
|
|||
/* mdb_dump.c - memory-mapped database dump tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define Z "I"
|
||||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
#define PRINT 1
|
||||
static int mode;
|
||||
|
||||
typedef struct flagbit {
|
||||
int bit;
|
||||
char *name;
|
||||
} flagbit;
|
||||
|
||||
flagbit dbflags[] = {
|
||||
{ MDB_REVERSEKEY, "reversekey" },
|
||||
{ MDB_DUPSORT, "dupsort" },
|
||||
{ MDB_INTEGERKEY, "integerkey" },
|
||||
{ MDB_DUPFIXED, "dupfixed" },
|
||||
{ MDB_INTEGERDUP, "integerdup" },
|
||||
{ MDB_REVERSEDUP, "reversedup" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static volatile sig_atomic_t gotsig;
|
||||
|
||||
static void dumpsig( int sig )
|
||||
{
|
||||
gotsig=1;
|
||||
}
|
||||
|
||||
static const char hexc[] = "0123456789abcdef";
|
||||
|
||||
static void hex(unsigned char c)
|
||||
{
|
||||
putchar(hexc[c >> 4]);
|
||||
putchar(hexc[c & 0xf]);
|
||||
}
|
||||
|
||||
static void text(MDB_val *v)
|
||||
{
|
||||
unsigned char *c, *end;
|
||||
|
||||
putchar(' ');
|
||||
c = v->mv_data;
|
||||
end = c + v->mv_size;
|
||||
while (c < end) {
|
||||
if (isprint(*c)) {
|
||||
putchar(*c);
|
||||
} else {
|
||||
putchar('\\');
|
||||
hex(*c);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void byte(MDB_val *v)
|
||||
{
|
||||
unsigned char *c, *end;
|
||||
|
||||
putchar(' ');
|
||||
c = v->mv_data;
|
||||
end = c + v->mv_size;
|
||||
while (c < end) {
|
||||
hex(*c++);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/* Dump in BDB-compatible format */
|
||||
static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
|
||||
{
|
||||
MDB_cursor *mc;
|
||||
MDB_stat ms;
|
||||
MDB_val key, data;
|
||||
MDB_envinfo info;
|
||||
unsigned int flags;
|
||||
int rc, i;
|
||||
|
||||
rc = mdb_dbi_flags(txn, dbi, &flags);
|
||||
if (rc) return rc;
|
||||
|
||||
rc = mdb_stat(txn, dbi, &ms);
|
||||
if (rc) return rc;
|
||||
|
||||
rc = mdb_env_info(mdb_txn_env(txn), &info);
|
||||
if (rc) return rc;
|
||||
|
||||
printf("VERSION=3\n");
|
||||
printf("format=%s\n", mode & PRINT ? "print" : "bytevalue");
|
||||
if (name)
|
||||
printf("database=%s\n", name);
|
||||
printf("type=btree\n");
|
||||
printf("mapsize=%" Y "u\n", info.me_mapsize);
|
||||
if (info.me_mapaddr)
|
||||
printf("mapaddr=%p\n", info.me_mapaddr);
|
||||
printf("maxreaders=%u\n", info.me_maxreaders);
|
||||
|
||||
if (flags & MDB_DUPSORT)
|
||||
printf("duplicates=1\n");
|
||||
|
||||
for (i=0; dbflags[i].bit; i++)
|
||||
if (flags & dbflags[i].bit)
|
||||
printf("%s=1\n", dbflags[i].name);
|
||||
|
||||
printf("db_pagesize=%d\n", ms.ms_psize);
|
||||
printf("HEADER=END\n");
|
||||
|
||||
rc = mdb_cursor_open(txn, dbi, &mc);
|
||||
if (rc) return rc;
|
||||
|
||||
while ((rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT) == MDB_SUCCESS)) {
|
||||
if (gotsig) {
|
||||
rc = EINTR;
|
||||
break;
|
||||
}
|
||||
if (mode & PRINT) {
|
||||
text(&key);
|
||||
text(&data);
|
||||
} else {
|
||||
byte(&key);
|
||||
byte(&data);
|
||||
}
|
||||
}
|
||||
printf("DATA=END\n");
|
||||
if (rc == MDB_NOTFOUND)
|
||||
rc = MDB_SUCCESS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, rc;
|
||||
MDB_env *env;
|
||||
MDB_txn *txn;
|
||||
MDB_dbi dbi;
|
||||
char *prog = argv[0];
|
||||
char *envname;
|
||||
char *subname = NULL;
|
||||
int alldbs = 0, envflags = 0, list = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(prog);
|
||||
}
|
||||
|
||||
/* -a: dump main DB and all subDBs
|
||||
* -s: dump only the named subDB
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -p: use printable characters
|
||||
* -f: write to file instead of stdout
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) dump only the main DB
|
||||
*/
|
||||
while ((i = getopt(argc, argv, "af:lnps:V")) != EOF) {
|
||||
switch(i) {
|
||||
case 'V':
|
||||
printf("%s\n", MDB_VERSION_STRING);
|
||||
exit(0);
|
||||
break;
|
||||
case 'l':
|
||||
list = 1;
|
||||
/*FALLTHROUGH*/;
|
||||
case 'a':
|
||||
if (subname)
|
||||
usage(prog);
|
||||
alldbs++;
|
||||
break;
|
||||
case 'f':
|
||||
if (freopen(optarg, "w", stdout) == NULL) {
|
||||
fprintf(stderr, "%s: %s: reopen: %s\n",
|
||||
prog, optarg, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'p':
|
||||
mode |= PRINT;
|
||||
break;
|
||||
case 's':
|
||||
if (alldbs)
|
||||
usage(prog);
|
||||
subname = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(prog);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage(prog);
|
||||
|
||||
#ifdef SIGPIPE
|
||||
signal(SIGPIPE, dumpsig);
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
signal(SIGHUP, dumpsig);
|
||||
#endif
|
||||
signal(SIGINT, dumpsig);
|
||||
signal(SIGTERM, dumpsig);
|
||||
|
||||
envname = argv[optind];
|
||||
rc = mdb_env_create(&env);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (alldbs || subname) {
|
||||
mdb_env_set_maxdbs(env, 2);
|
||||
}
|
||||
|
||||
rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
rc = mdb_open(txn, subname, 0, &dbi);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
|
||||
if (alldbs) {
|
||||
MDB_cursor *cursor;
|
||||
MDB_val key;
|
||||
int count = 0;
|
||||
|
||||
rc = mdb_cursor_open(txn, dbi, &cursor);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
|
||||
char *str;
|
||||
MDB_dbi db2;
|
||||
if (memchr(key.mv_data, '\0', key.mv_size))
|
||||
continue;
|
||||
count++;
|
||||
str = malloc(key.mv_size+1);
|
||||
memcpy(str, key.mv_data, key.mv_size);
|
||||
str[key.mv_size] = '\0';
|
||||
rc = mdb_open(txn, str, 0, &db2);
|
||||
if (rc == MDB_SUCCESS) {
|
||||
if (list) {
|
||||
printf("%s\n", str);
|
||||
list++;
|
||||
} else {
|
||||
rc = dumpit(txn, db2, str);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
mdb_close(env, db2);
|
||||
}
|
||||
free(str);
|
||||
if (rc) continue;
|
||||
}
|
||||
mdb_cursor_close(cursor);
|
||||
if (!count) {
|
||||
fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname);
|
||||
rc = MDB_NOTFOUND;
|
||||
} else if (rc == MDB_NOTFOUND) {
|
||||
rc = MDB_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
rc = dumpit(txn, dbi, subname);
|
||||
}
|
||||
if (rc && rc != MDB_NOTFOUND)
|
||||
fprintf(stderr, "%s: %s: %s\n", prog, envname, mdb_strerror(rc));
|
||||
|
||||
mdb_close(env, dbi);
|
||||
txn_abort:
|
||||
mdb_txn_abort(txn);
|
||||
env_close:
|
||||
mdb_env_close(env);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
.TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_load \- LMDB environment import tool
|
||||
.SH SYNOPSIS
|
||||
.B mdb_load
|
||||
[\c
|
||||
.BR \-V ]
|
||||
[\c
|
||||
.BI \-f \ file\fR]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BI \-s \ subdb\fR]
|
||||
[\c
|
||||
.BR \-N ]
|
||||
[\c
|
||||
.BR \-T ]
|
||||
.BR \ envpath
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B mdb_load
|
||||
utility reads from the standard input and loads it into the
|
||||
LMDB environment
|
||||
.BR envpath .
|
||||
|
||||
The input to
|
||||
.B mdb_load
|
||||
must be in the output format specified by the
|
||||
.BR mdb_dump (1)
|
||||
utility or as specified by the
|
||||
.B -T
|
||||
option below.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-V
|
||||
Write the library version number to the standard output, and exit.
|
||||
.TP
|
||||
.BR \-a
|
||||
Append all records in the order they appear in the input. The input is assumed to already be
|
||||
in correctly sorted order and no sorting or checking for redundant values will be performed.
|
||||
This option must be used to reload data that was produced by running
|
||||
.B mdb_dump
|
||||
on a database that uses custom compare functions.
|
||||
.TP
|
||||
.BR \-f \ file
|
||||
Read from the specified file instead of from the standard input.
|
||||
.TP
|
||||
.BR \-n
|
||||
Load an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-s \ subdb
|
||||
Load a specific subdatabase. If no database is specified, data is loaded into the main database.
|
||||
.TP
|
||||
.BR \-N
|
||||
Don't overwrite existing records when loading into an already existing database; just skip them.
|
||||
.TP
|
||||
.BR \-T
|
||||
Load data from simple text files. The input must be paired lines of text, where the first
|
||||
line of the pair is the key item, and the second line of the pair is its corresponding
|
||||
data item.
|
||||
|
||||
A simple escape mechanism, where newline and backslash (\\) characters are special, is
|
||||
applied to the text input. Newline characters are interpreted as record separators.
|
||||
Backslash characters in the text will be interpreted in one of two ways: If the backslash
|
||||
character precedes another backslash character, the pair will be interpreted as a literal
|
||||
backslash. If the backslash character precedes any other character, the two characters
|
||||
following the backslash will be interpreted as a hexadecimal specification of a single
|
||||
character; for example, \\0a is a newline character in the ASCII character set.
|
||||
|
||||
For this reason, any backslash or newline characters that naturally occur in the text
|
||||
input must be escaped to avoid misinterpretation by
|
||||
.BR mdb_load .
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
Errors result in a non-zero exit status and
|
||||
a diagnostic message being written to standard error.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR mdb_dump (1)
|
||||
.SH AUTHOR
|
||||
Howard Chu of Symas Corporation <http://www.symas.com>
|
||||
|
|
@ -1,499 +0,0 @@
|
|||
/* mdb_load.c - memory-mapped database load tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define PRINT 1
|
||||
#define NOHDR 2
|
||||
static int mode;
|
||||
|
||||
static char *subname = NULL;
|
||||
|
||||
static size_t lineno;
|
||||
static int version;
|
||||
|
||||
static int flags;
|
||||
|
||||
static char *prog;
|
||||
|
||||
static int Eof;
|
||||
|
||||
static MDB_envinfo info;
|
||||
|
||||
static MDB_val kbuf, dbuf;
|
||||
static MDB_val k0buf;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define Z "I"
|
||||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
#define STRLENOF(s) (sizeof(s)-1)
|
||||
|
||||
typedef struct flagbit {
|
||||
int bit;
|
||||
char *name;
|
||||
int len;
|
||||
} flagbit;
|
||||
|
||||
#define S(s) s, STRLENOF(s)
|
||||
|
||||
flagbit dbflags[] = {
|
||||
{ MDB_REVERSEKEY, S("reversekey") },
|
||||
{ MDB_DUPSORT, S("dupsort") },
|
||||
{ MDB_INTEGERKEY, S("integerkey") },
|
||||
{ MDB_DUPFIXED, S("dupfixed") },
|
||||
{ MDB_INTEGERDUP, S("integerdup") },
|
||||
{ MDB_REVERSEDUP, S("reversedup") },
|
||||
{ 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static void readhdr(void)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) {
|
||||
lineno++;
|
||||
if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) {
|
||||
version=atoi((char *)dbuf.mv_data+STRLENOF("VERSION="));
|
||||
if (version > 3) {
|
||||
fprintf(stderr, "%s: line %" Z "d: unsupported VERSION %d\n",
|
||||
prog, lineno, version);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (!strncmp(dbuf.mv_data, "HEADER=END", STRLENOF("HEADER=END"))) {
|
||||
break;
|
||||
} else if (!strncmp(dbuf.mv_data, "format=", STRLENOF("format="))) {
|
||||
if (!strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "print", STRLENOF("print")))
|
||||
mode |= PRINT;
|
||||
else if (strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "bytevalue", STRLENOF("bytevalue"))) {
|
||||
fprintf(stderr, "%s: line %" Z "d: unsupported FORMAT %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("FORMAT="));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (!strncmp(dbuf.mv_data, "database=", STRLENOF("database="))) {
|
||||
ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
|
||||
if (ptr) *ptr = '\0';
|
||||
if (subname) free(subname);
|
||||
subname = strdup((char *)dbuf.mv_data+STRLENOF("database="));
|
||||
} else if (!strncmp(dbuf.mv_data, "type=", STRLENOF("type="))) {
|
||||
if (strncmp((char *)dbuf.mv_data+STRLENOF("type="), "btree", STRLENOF("btree"))) {
|
||||
fprintf(stderr, "%s: line %" Z "d: unsupported type %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("type="));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (!strncmp(dbuf.mv_data, "mapaddr=", STRLENOF("mapaddr="))) {
|
||||
int i;
|
||||
ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
|
||||
if (ptr) *ptr = '\0';
|
||||
i = sscanf((char *)dbuf.mv_data+STRLENOF("mapaddr="), "%p", &info.me_mapaddr);
|
||||
if (i != 1) {
|
||||
fprintf(stderr, "%s: line %" Z "d: invalid mapaddr %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapaddr="));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (!strncmp(dbuf.mv_data, "mapsize=", STRLENOF("mapsize="))) {
|
||||
int i;
|
||||
ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
|
||||
if (ptr) *ptr = '\0';
|
||||
i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Y "u", &info.me_mapsize);
|
||||
if (i != 1) {
|
||||
fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize="));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (!strncmp(dbuf.mv_data, "maxreaders=", STRLENOF("maxreaders="))) {
|
||||
int i;
|
||||
ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
|
||||
if (ptr) *ptr = '\0';
|
||||
i = sscanf((char *)dbuf.mv_data+STRLENOF("maxreaders="), "%u", &info.me_maxreaders);
|
||||
if (i != 1) {
|
||||
fprintf(stderr, "%s: line %" Z "d: invalid maxreaders %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data+STRLENOF("maxreaders="));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
int i;
|
||||
for (i=0; dbflags[i].bit; i++) {
|
||||
if (!strncmp(dbuf.mv_data, dbflags[i].name, dbflags[i].len) &&
|
||||
((char *)dbuf.mv_data)[dbflags[i].len] == '=') {
|
||||
flags |= dbflags[i].bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dbflags[i].bit) {
|
||||
ptr = memchr(dbuf.mv_data, '=', dbuf.mv_size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "%s: line %" Z "d: unexpected format\n",
|
||||
prog, lineno);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
*ptr = '\0';
|
||||
fprintf(stderr, "%s: line %" Z "d: unrecognized keyword ignored: %s\n",
|
||||
prog, lineno, (char *)dbuf.mv_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void badend(void)
|
||||
{
|
||||
fprintf(stderr, "%s: line %" Z "d: unexpected end of input\n",
|
||||
prog, lineno);
|
||||
}
|
||||
|
||||
static int unhex(unsigned char *c2)
|
||||
{
|
||||
int x, c;
|
||||
x = *c2++ & 0x4f;
|
||||
if (x & 0x40)
|
||||
x -= 55;
|
||||
c = x << 4;
|
||||
x = *c2 & 0x4f;
|
||||
if (x & 0x40)
|
||||
x -= 55;
|
||||
c |= x;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int readline(MDB_val *out, MDB_val *buf)
|
||||
{
|
||||
unsigned char *c1, *c2, *end;
|
||||
size_t len, l2;
|
||||
int c;
|
||||
|
||||
if (!(mode & NOHDR)) {
|
||||
c = fgetc(stdin);
|
||||
if (c == EOF) {
|
||||
Eof = 1;
|
||||
return EOF;
|
||||
}
|
||||
if (c != ' ') {
|
||||
lineno++;
|
||||
if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
|
||||
badend:
|
||||
Eof = 1;
|
||||
badend();
|
||||
return EOF;
|
||||
}
|
||||
if (c == 'D' && !strncmp(buf->mv_data, "ATA=END", STRLENOF("ATA=END")))
|
||||
return EOF;
|
||||
goto badend;
|
||||
}
|
||||
}
|
||||
if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
|
||||
Eof = 1;
|
||||
return EOF;
|
||||
}
|
||||
lineno++;
|
||||
|
||||
c1 = buf->mv_data;
|
||||
len = strlen((char *)c1);
|
||||
l2 = len;
|
||||
|
||||
/* Is buffer too short? */
|
||||
while (c1[len-1] != '\n') {
|
||||
buf->mv_data = realloc(buf->mv_data, buf->mv_size*2);
|
||||
if (!buf->mv_data) {
|
||||
Eof = 1;
|
||||
fprintf(stderr, "%s: line %" Z "d: out of memory, line too long\n",
|
||||
prog, lineno);
|
||||
return EOF;
|
||||
}
|
||||
c1 = buf->mv_data;
|
||||
c1 += l2;
|
||||
if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) {
|
||||
Eof = 1;
|
||||
badend();
|
||||
return EOF;
|
||||
}
|
||||
buf->mv_size *= 2;
|
||||
len = strlen((char *)c1);
|
||||
l2 += len;
|
||||
}
|
||||
c1 = c2 = buf->mv_data;
|
||||
len = l2;
|
||||
c1[--len] = '\0';
|
||||
end = c1 + len;
|
||||
|
||||
if (mode & PRINT) {
|
||||
while (c2 < end) {
|
||||
if (*c2 == '\\') {
|
||||
if (c2[1] == '\\') {
|
||||
c1++; c2 += 2;
|
||||
} else {
|
||||
if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) {
|
||||
Eof = 1;
|
||||
badend();
|
||||
return EOF;
|
||||
}
|
||||
*c1++ = unhex(++c2);
|
||||
c2 += 2;
|
||||
}
|
||||
} else {
|
||||
c1++; c2++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* odd length not allowed */
|
||||
if (len & 1) {
|
||||
Eof = 1;
|
||||
badend();
|
||||
return EOF;
|
||||
}
|
||||
while (c2 < end) {
|
||||
if (!isxdigit(*c2) || !isxdigit(c2[1])) {
|
||||
Eof = 1;
|
||||
badend();
|
||||
return EOF;
|
||||
}
|
||||
*c1++ = unhex(c2);
|
||||
c2 += 2;
|
||||
}
|
||||
}
|
||||
c2 = out->mv_data = buf->mv_data;
|
||||
out->mv_size = c1 - c2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int greater(const MDB_val *a, const MDB_val *b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, rc;
|
||||
MDB_env *env;
|
||||
MDB_txn *txn;
|
||||
MDB_cursor *mc;
|
||||
MDB_dbi dbi;
|
||||
char *envname;
|
||||
int envflags = 0, putflags = 0;
|
||||
int dohdr = 0, append = 0;
|
||||
MDB_val prevk;
|
||||
|
||||
prog = argv[0];
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
/* -a: append records in input order
|
||||
* -f: load file instead of stdin
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -s: load into named subDB
|
||||
* -N: use NOOVERWRITE on puts
|
||||
* -T: read plaintext
|
||||
* -V: print version and exit
|
||||
*/
|
||||
while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) {
|
||||
switch(i) {
|
||||
case 'V':
|
||||
printf("%s\n", MDB_VERSION_STRING);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (freopen(optarg, "r", stdin) == NULL) {
|
||||
fprintf(stderr, "%s: %s: reopen: %s\n",
|
||||
prog, optarg, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 's':
|
||||
subname = strdup(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
putflags = MDB_NOOVERWRITE|MDB_NODUPDATA;
|
||||
break;
|
||||
case 'T':
|
||||
mode |= NOHDR | PRINT;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage();
|
||||
|
||||
dbuf.mv_size = 4096;
|
||||
dbuf.mv_data = malloc(dbuf.mv_size);
|
||||
|
||||
if (!(mode & NOHDR))
|
||||
readhdr();
|
||||
|
||||
envname = argv[optind];
|
||||
rc = mdb_env_create(&env);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
mdb_env_set_maxdbs(env, 2);
|
||||
|
||||
if (info.me_maxreaders)
|
||||
mdb_env_set_maxreaders(env, info.me_maxreaders);
|
||||
|
||||
if (info.me_mapsize)
|
||||
mdb_env_set_mapsize(env, info.me_mapsize);
|
||||
|
||||
if (info.me_mapaddr)
|
||||
envflags |= MDB_FIXEDMAP;
|
||||
|
||||
rc = mdb_env_open(env, envname, envflags, 0664);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2;
|
||||
kbuf.mv_data = malloc(kbuf.mv_size * 2);
|
||||
k0buf.mv_size = kbuf.mv_size;
|
||||
k0buf.mv_data = (char *)kbuf.mv_data + kbuf.mv_size;
|
||||
prevk.mv_size = 0;
|
||||
prevk.mv_data = k0buf.mv_data;
|
||||
|
||||
while(!Eof) {
|
||||
MDB_val key, data;
|
||||
int batch = 0;
|
||||
flags = 0;
|
||||
int appflag;
|
||||
|
||||
if (!dohdr) {
|
||||
dohdr = 1;
|
||||
} else if (!(mode & NOHDR))
|
||||
readhdr();
|
||||
|
||||
rc = mdb_txn_begin(env, NULL, 0, &txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
rc = mdb_open(txn, subname, flags|MDB_CREATE, &dbi);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
if (append) {
|
||||
mdb_set_compare(txn, dbi, greater);
|
||||
if (flags & MDB_DUPSORT)
|
||||
mdb_set_dupsort(txn, dbi, greater);
|
||||
}
|
||||
|
||||
rc = mdb_cursor_open(txn, dbi, &mc);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
rc = readline(&key, &kbuf);
|
||||
if (rc) /* rc == EOF */
|
||||
break;
|
||||
|
||||
rc = readline(&data, &dbuf);
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s: line %" Z "d: failed to read key value\n", prog, lineno);
|
||||
goto txn_abort;
|
||||
}
|
||||
|
||||
if (append) {
|
||||
appflag = MDB_APPEND;
|
||||
if (flags & MDB_DUPSORT) {
|
||||
if (prevk.mv_size == key.mv_size && !memcmp(prevk.mv_data, key.mv_data, key.mv_size))
|
||||
appflag = MDB_APPENDDUP;
|
||||
else {
|
||||
memcpy(prevk.mv_data, key.mv_data, key.mv_size);
|
||||
prevk.mv_size = key.mv_size;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appflag = 0;
|
||||
}
|
||||
rc = mdb_cursor_put(mc, &key, &data, putflags|appflag);
|
||||
if (rc == MDB_KEYEXIST && putflags)
|
||||
continue;
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_put failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
batch++;
|
||||
if (batch == 100) {
|
||||
rc = mdb_txn_commit(txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
|
||||
prog, lineno, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
rc = mdb_txn_begin(env, NULL, 0, &txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
rc = mdb_cursor_open(txn, dbi, &mc);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
batch = 0;
|
||||
}
|
||||
}
|
||||
rc = mdb_txn_commit(txn);
|
||||
txn = NULL;
|
||||
if (rc) {
|
||||
fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
|
||||
prog, lineno, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
mdb_dbi_close(env, dbi);
|
||||
}
|
||||
|
||||
txn_abort:
|
||||
mdb_txn_abort(txn);
|
||||
env_close:
|
||||
mdb_env_close(env);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
.TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14"
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.SH NAME
|
||||
mdb_stat \- LMDB environment status tool
|
||||
.SH SYNOPSIS
|
||||
.B mdb_stat
|
||||
[\c
|
||||
.BR \-V ]
|
||||
[\c
|
||||
.BR \-e ]
|
||||
[\c
|
||||
.BR \-f [ f [ f ]]]
|
||||
[\c
|
||||
.BR \-n ]
|
||||
[\c
|
||||
.BR \-v ]
|
||||
[\c
|
||||
.BR \-r [ r ]]
|
||||
[\c
|
||||
.BR \-a \ |
|
||||
.BI \-s \ subdb\fR]
|
||||
.BR \ envpath
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B mdb_stat
|
||||
utility displays the status of an LMDB environment.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-V
|
||||
Write the library version number to the standard output, and exit.
|
||||
.TP
|
||||
.BR \-e
|
||||
Display information about the database environment.
|
||||
.TP
|
||||
.BR \-f
|
||||
Display information about the environment freelist.
|
||||
If \fB\-ff\fP is given, summarize each freelist entry.
|
||||
If \fB\-fff\fP is given, display the full list of page IDs in the freelist.
|
||||
.TP
|
||||
.BR \-n
|
||||
Display the status of an LMDB database which does not use subdirectories.
|
||||
.TP
|
||||
.BR \-v
|
||||
Use the previous environment state instead of the latest state.
|
||||
This may be useful if the latest state has been corrupted.
|
||||
.TP
|
||||
.BR \-r
|
||||
Display information about the environment reader table.
|
||||
Shows the process ID, thread ID, and transaction ID for each active
|
||||
reader slot. The process ID and transaction ID are in decimal, the
|
||||
thread ID is in hexadecimal. The transaction ID is displayed as "-"
|
||||
if the reader does not currently have a read transaction open.
|
||||
If \fB\-rr\fP is given, check for stale entries in the reader
|
||||
table and clear them. The reader table will be printed again
|
||||
after the check is performed.
|
||||
.TP
|
||||
.BR \-a
|
||||
Display the status of all of the subdatabases in the environment.
|
||||
.TP
|
||||
.BR \-s \ subdb
|
||||
Display the status of a specific subdatabase.
|
||||
.SH DIAGNOSTICS
|
||||
Exit status is zero if no errors occur.
|
||||
Errors result in a non-zero exit status and
|
||||
a diagnostic message being written to standard error.
|
||||
.SH "SEE ALSO"
|
||||
.BR mdb_copy (1)
|
||||
.SH AUTHOR
|
||||
Howard Chu of Symas Corporation <http://www.symas.com>
|
||||
|
|
@ -1,276 +0,0 @@
|
|||
/* mdb_stat.c - memory-mapped database status tool */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define Z "I"
|
||||
#else
|
||||
#define Z "z"
|
||||
#endif
|
||||
#ifdef MDB_VL32
|
||||
#ifdef _WIN32
|
||||
#define Y "I64"
|
||||
#else
|
||||
#define Y "ll"
|
||||
#endif
|
||||
#else
|
||||
#define Y Z
|
||||
#endif
|
||||
|
||||
static void prstat(MDB_stat *ms)
|
||||
{
|
||||
#if 0
|
||||
printf(" Page size: %u\n", ms->ms_psize);
|
||||
#endif
|
||||
printf(" Tree depth: %u\n", ms->ms_depth);
|
||||
printf(" Branch pages: %"Y"u\n", ms->ms_branch_pages);
|
||||
printf(" Leaf pages: %"Y"u\n", ms->ms_leaf_pages);
|
||||
printf(" Overflow pages: %"Y"u\n", ms->ms_overflow_pages);
|
||||
printf(" Entries: %"Y"u\n", ms->ms_entries);
|
||||
}
|
||||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, rc;
|
||||
MDB_env *env;
|
||||
MDB_txn *txn;
|
||||
MDB_dbi dbi;
|
||||
MDB_stat mst;
|
||||
MDB_envinfo mei;
|
||||
char *prog = argv[0];
|
||||
char *envname;
|
||||
char *subname = NULL;
|
||||
int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(prog);
|
||||
}
|
||||
|
||||
/* -a: print stat of main DB and all subDBs
|
||||
* -s: print stat of only the named subDB
|
||||
* -e: print env info
|
||||
* -f: print freelist info
|
||||
* -r: print reader info
|
||||
* -n: use NOSUBDIR flag on env_open
|
||||
* -v: use previous snapshot
|
||||
* -V: print version and exit
|
||||
* (default) print stat of only the main DB
|
||||
*/
|
||||
while ((i = getopt(argc, argv, "Vaefnrs:")) != EOF) {
|
||||
switch(i) {
|
||||
case 'V':
|
||||
printf("%s\n", MDB_VERSION_STRING);
|
||||
exit(0);
|
||||
break;
|
||||
case 'a':
|
||||
if (subname)
|
||||
usage(prog);
|
||||
alldbs++;
|
||||
break;
|
||||
case 'e':
|
||||
envinfo++;
|
||||
break;
|
||||
case 'f':
|
||||
freinfo++;
|
||||
break;
|
||||
case 'n':
|
||||
envflags |= MDB_NOSUBDIR;
|
||||
break;
|
||||
case 'v':
|
||||
envflags |= MDB_PREVSNAPSHOT;
|
||||
break;
|
||||
case 'r':
|
||||
rdrinfo++;
|
||||
break;
|
||||
case 's':
|
||||
if (alldbs)
|
||||
usage(prog);
|
||||
subname = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(prog);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1)
|
||||
usage(prog);
|
||||
|
||||
envname = argv[optind];
|
||||
rc = mdb_env_create(&env);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (alldbs || subname) {
|
||||
mdb_env_set_maxdbs(env, 4);
|
||||
}
|
||||
|
||||
rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
if (envinfo) {
|
||||
(void)mdb_env_stat(env, &mst);
|
||||
(void)mdb_env_info(env, &mei);
|
||||
printf("Environment Info\n");
|
||||
printf(" Map address: %p\n", mei.me_mapaddr);
|
||||
printf(" Map size: %"Y"u\n", mei.me_mapsize);
|
||||
printf(" Page size: %u\n", mst.ms_psize);
|
||||
printf(" Max pages: %"Y"u\n", mei.me_mapsize / mst.ms_psize);
|
||||
printf(" Number of pages used: %"Y"u\n", mei.me_last_pgno+1);
|
||||
printf(" Last transaction ID: %"Y"u\n", mei.me_last_txnid);
|
||||
printf(" Max readers: %u\n", mei.me_maxreaders);
|
||||
printf(" Number of readers used: %u\n", mei.me_numreaders);
|
||||
}
|
||||
|
||||
if (rdrinfo) {
|
||||
printf("Reader Table Status\n");
|
||||
rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout);
|
||||
if (rdrinfo > 1) {
|
||||
int dead;
|
||||
mdb_reader_check(env, &dead);
|
||||
printf(" %d stale readers cleared.\n", dead);
|
||||
rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout);
|
||||
}
|
||||
if (!(subname || alldbs || freinfo))
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
if (freinfo) {
|
||||
MDB_cursor *cursor;
|
||||
MDB_val key, data;
|
||||
size_t pages = 0, *iptr;
|
||||
|
||||
printf("Freelist Status\n");
|
||||
dbi = 0;
|
||||
rc = mdb_cursor_open(txn, dbi, &cursor);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
rc = mdb_stat(txn, dbi, &mst);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
prstat(&mst);
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
iptr = data.mv_data;
|
||||
pages += *iptr;
|
||||
if (freinfo > 1) {
|
||||
char *bad = "";
|
||||
size_t pg, prev;
|
||||
ssize_t i, j, span = 0;
|
||||
j = *iptr++;
|
||||
for (i = j, prev = 1; --i >= 0; ) {
|
||||
pg = iptr[i];
|
||||
if (pg <= prev)
|
||||
bad = " [bad sequence]";
|
||||
prev = pg;
|
||||
pg += span;
|
||||
for (; i >= span && iptr[i-span] == pg; span++, pg++) ;
|
||||
}
|
||||
printf(" Transaction %"Z"u, %"Z"d pages, maxspan %"Z"d%s\n",
|
||||
*(size_t *)key.mv_data, j, span, bad);
|
||||
if (freinfo > 2) {
|
||||
for (--j; j >= 0; ) {
|
||||
pg = iptr[j];
|
||||
for (span=1; --j >= 0 && iptr[j] == pg+span; span++) ;
|
||||
printf(span>1 ? " %9"Z"u[%"Z"d]\n" : " %9"Z"u\n",
|
||||
pg, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mdb_cursor_close(cursor);
|
||||
printf(" Free pages: %"Z"u\n", pages);
|
||||
}
|
||||
|
||||
rc = mdb_open(txn, subname, 0, &dbi);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
|
||||
rc = mdb_stat(txn, dbi, &mst);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
printf("Status of %s\n", subname ? subname : "Main DB");
|
||||
prstat(&mst);
|
||||
|
||||
if (alldbs) {
|
||||
MDB_cursor *cursor;
|
||||
MDB_val key;
|
||||
|
||||
rc = mdb_cursor_open(txn, dbi, &cursor);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
|
||||
char *str;
|
||||
MDB_dbi db2;
|
||||
if (memchr(key.mv_data, '\0', key.mv_size))
|
||||
continue;
|
||||
str = malloc(key.mv_size+1);
|
||||
memcpy(str, key.mv_data, key.mv_size);
|
||||
str[key.mv_size] = '\0';
|
||||
rc = mdb_open(txn, str, 0, &db2);
|
||||
if (rc == MDB_SUCCESS)
|
||||
printf("Status of %s\n", str);
|
||||
free(str);
|
||||
if (rc) continue;
|
||||
rc = mdb_stat(txn, db2, &mst);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
|
||||
goto txn_abort;
|
||||
}
|
||||
prstat(&mst);
|
||||
mdb_close(env, db2);
|
||||
}
|
||||
mdb_cursor_close(cursor);
|
||||
}
|
||||
|
||||
if (rc == MDB_NOTFOUND)
|
||||
rc = MDB_SUCCESS;
|
||||
|
||||
mdb_close(env, dbi);
|
||||
txn_abort:
|
||||
mdb_txn_abort(txn);
|
||||
env_close:
|
||||
mdb_env_close(env);
|
||||
|
||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,420 +0,0 @@
|
|||
/** @file midl.c
|
||||
* @brief ldap bdb back-end ID List functions */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2015 The OpenLDAP Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include "midl.h"
|
||||
|
||||
/** @defgroup internal LMDB Internals
|
||||
* @{
|
||||
*/
|
||||
/** @defgroup idls ID List Management
|
||||
* @{
|
||||
*/
|
||||
#define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
|
||||
|
||||
unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
|
||||
{
|
||||
/*
|
||||
* binary search of id in ids
|
||||
* if found, returns position of id
|
||||
* if not found, returns first position greater than id
|
||||
*/
|
||||
unsigned base = 0;
|
||||
unsigned cursor = 1;
|
||||
int val = 0;
|
||||
unsigned n = ids[0];
|
||||
|
||||
while( 0 < n ) {
|
||||
unsigned pivot = n >> 1;
|
||||
cursor = base + pivot + 1;
|
||||
val = CMP( ids[cursor], id );
|
||||
|
||||
if( val < 0 ) {
|
||||
n = pivot;
|
||||
|
||||
} else if ( val > 0 ) {
|
||||
base = cursor;
|
||||
n -= pivot + 1;
|
||||
|
||||
} else {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
if( val > 0 ) {
|
||||
++cursor;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
#if 0 /* superseded by append/sort */
|
||||
int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
|
||||
{
|
||||
unsigned x, i;
|
||||
|
||||
x = mdb_midl_search( ids, id );
|
||||
assert( x > 0 );
|
||||
|
||||
if( x < 1 ) {
|
||||
/* internal error */
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( x <= ids[0] && ids[x] == id ) {
|
||||
/* duplicate */
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ++ids[0] >= MDB_IDL_DB_MAX ) {
|
||||
/* no room */
|
||||
--ids[0];
|
||||
return -2;
|
||||
|
||||
} else {
|
||||
/* insert id */
|
||||
for (i=ids[0]; i>x; i--)
|
||||
ids[i] = ids[i-1];
|
||||
ids[x] = id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
MDB_IDL mdb_midl_alloc(int num)
|
||||
{
|
||||
MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
|
||||
if (ids) {
|
||||
*ids++ = num;
|
||||
*ids = 0;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
void mdb_midl_free(MDB_IDL ids)
|
||||
{
|
||||
if (ids)
|
||||
free(ids-1);
|
||||
}
|
||||
|
||||
void mdb_midl_shrink( MDB_IDL *idp )
|
||||
{
|
||||
MDB_IDL ids = *idp;
|
||||
if (*(--ids) > MDB_IDL_UM_MAX &&
|
||||
(ids = realloc(ids, (MDB_IDL_UM_MAX+2) * sizeof(MDB_ID))))
|
||||
{
|
||||
*ids++ = MDB_IDL_UM_MAX;
|
||||
*idp = ids;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdb_midl_grow( MDB_IDL *idp, int num )
|
||||
{
|
||||
MDB_IDL idn = *idp-1;
|
||||
/* grow it */
|
||||
idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID));
|
||||
if (!idn)
|
||||
return ENOMEM;
|
||||
*idn++ += num;
|
||||
*idp = idn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_need( MDB_IDL *idp, unsigned num )
|
||||
{
|
||||
MDB_IDL ids = *idp;
|
||||
num += ids[0];
|
||||
if (num > ids[-1]) {
|
||||
num = (num + num/4 + (256 + 2)) & -256;
|
||||
if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
|
||||
return ENOMEM;
|
||||
*ids++ = num - 2;
|
||||
*idp = ids;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
|
||||
{
|
||||
MDB_IDL ids = *idp;
|
||||
/* Too big? */
|
||||
if (ids[0] >= ids[-1]) {
|
||||
if (mdb_midl_grow(idp, MDB_IDL_UM_MAX))
|
||||
return ENOMEM;
|
||||
ids = *idp;
|
||||
}
|
||||
ids[0]++;
|
||||
ids[ids[0]] = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
|
||||
{
|
||||
MDB_IDL ids = *idp;
|
||||
/* Too big? */
|
||||
if (ids[0] + app[0] >= ids[-1]) {
|
||||
if (mdb_midl_grow(idp, app[0]))
|
||||
return ENOMEM;
|
||||
ids = *idp;
|
||||
}
|
||||
memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID));
|
||||
ids[0] += app[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
|
||||
{
|
||||
MDB_ID *ids = *idp, len = ids[0];
|
||||
/* Too big? */
|
||||
if (len + n > ids[-1]) {
|
||||
if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX))
|
||||
return ENOMEM;
|
||||
ids = *idp;
|
||||
}
|
||||
ids[0] = len + n;
|
||||
ids += len;
|
||||
while (n)
|
||||
ids[n--] = id++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
|
||||
{
|
||||
MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k;
|
||||
idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */
|
||||
old_id = idl[j];
|
||||
while (i) {
|
||||
merge_id = merge[i--];
|
||||
for (; old_id < merge_id; old_id = idl[--j])
|
||||
idl[k--] = old_id;
|
||||
idl[k--] = merge_id;
|
||||
}
|
||||
idl[0] = total;
|
||||
}
|
||||
|
||||
/* Quicksort + Insertion sort for small arrays */
|
||||
|
||||
#define SMALL 8
|
||||
#define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; }
|
||||
|
||||
void
|
||||
mdb_midl_sort( MDB_IDL ids )
|
||||
{
|
||||
/* Max possible depth of int-indexed tree * 2 items/level */
|
||||
int istack[sizeof(int)*CHAR_BIT * 2];
|
||||
int i,j,k,l,ir,jstack;
|
||||
MDB_ID a, itmp;
|
||||
|
||||
ir = (int)ids[0];
|
||||
l = 1;
|
||||
jstack = 0;
|
||||
for(;;) {
|
||||
if (ir - l < SMALL) { /* Insertion sort */
|
||||
for (j=l+1;j<=ir;j++) {
|
||||
a = ids[j];
|
||||
for (i=j-1;i>=1;i--) {
|
||||
if (ids[i] >= a) break;
|
||||
ids[i+1] = ids[i];
|
||||
}
|
||||
ids[i+1] = a;
|
||||
}
|
||||
if (jstack == 0) break;
|
||||
ir = istack[jstack--];
|
||||
l = istack[jstack--];
|
||||
} else {
|
||||
k = (l + ir) >> 1; /* Choose median of left, center, right */
|
||||
MIDL_SWAP(ids[k], ids[l+1]);
|
||||
if (ids[l] < ids[ir]) {
|
||||
MIDL_SWAP(ids[l], ids[ir]);
|
||||
}
|
||||
if (ids[l+1] < ids[ir]) {
|
||||
MIDL_SWAP(ids[l+1], ids[ir]);
|
||||
}
|
||||
if (ids[l] < ids[l+1]) {
|
||||
MIDL_SWAP(ids[l], ids[l+1]);
|
||||
}
|
||||
i = l+1;
|
||||
j = ir;
|
||||
a = ids[l+1];
|
||||
for(;;) {
|
||||
do i++; while(ids[i] > a);
|
||||
do j--; while(ids[j] < a);
|
||||
if (j < i) break;
|
||||
MIDL_SWAP(ids[i],ids[j]);
|
||||
}
|
||||
ids[l+1] = ids[j];
|
||||
ids[j] = a;
|
||||
jstack += 2;
|
||||
if (ir-i+1 >= j-l) {
|
||||
istack[jstack] = ir;
|
||||
istack[jstack-1] = i;
|
||||
ir = j-1;
|
||||
} else {
|
||||
istack[jstack] = j-1;
|
||||
istack[jstack-1] = l;
|
||||
l = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
|
||||
{
|
||||
/*
|
||||
* binary search of id in ids
|
||||
* if found, returns position of id
|
||||
* if not found, returns first position greater than id
|
||||
*/
|
||||
unsigned base = 0;
|
||||
unsigned cursor = 1;
|
||||
int val = 0;
|
||||
unsigned n = (unsigned)ids[0].mid;
|
||||
|
||||
while( 0 < n ) {
|
||||
unsigned pivot = n >> 1;
|
||||
cursor = base + pivot + 1;
|
||||
val = CMP( id, ids[cursor].mid );
|
||||
|
||||
if( val < 0 ) {
|
||||
n = pivot;
|
||||
|
||||
} else if ( val > 0 ) {
|
||||
base = cursor;
|
||||
n -= pivot + 1;
|
||||
|
||||
} else {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
if( val > 0 ) {
|
||||
++cursor;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
|
||||
{
|
||||
unsigned x, i;
|
||||
|
||||
x = mdb_mid2l_search( ids, id->mid );
|
||||
|
||||
if( x < 1 ) {
|
||||
/* internal error */
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( x <= ids[0].mid && ids[x].mid == id->mid ) {
|
||||
/* duplicate */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ids[0].mid >= MDB_IDL_UM_MAX ) {
|
||||
/* too big */
|
||||
return -2;
|
||||
|
||||
} else {
|
||||
/* insert id */
|
||||
ids[0].mid++;
|
||||
for (i=(unsigned)ids[0].mid; i>x; i--)
|
||||
ids[i] = ids[i-1];
|
||||
ids[x] = *id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
|
||||
{
|
||||
/* Too big? */
|
||||
if (ids[0].mid >= MDB_IDL_UM_MAX) {
|
||||
return -2;
|
||||
}
|
||||
ids[0].mid++;
|
||||
ids[ids[0].mid] = *id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MDB_VL32
|
||||
unsigned mdb_mid3l_search( MDB_ID3L ids, MDB_ID id )
|
||||
{
|
||||
/*
|
||||
* binary search of id in ids
|
||||
* if found, returns position of id
|
||||
* if not found, returns first position greater than id
|
||||
*/
|
||||
unsigned base = 0;
|
||||
unsigned cursor = 1;
|
||||
int val = 0;
|
||||
unsigned n = (unsigned)ids[0].mid;
|
||||
|
||||
while( 0 < n ) {
|
||||
unsigned pivot = n >> 1;
|
||||
cursor = base + pivot + 1;
|
||||
val = CMP( id, ids[cursor].mid );
|
||||
|
||||
if( val < 0 ) {
|
||||
n = pivot;
|
||||
|
||||
} else if ( val > 0 ) {
|
||||
base = cursor;
|
||||
n -= pivot + 1;
|
||||
|
||||
} else {
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
if( val > 0 ) {
|
||||
++cursor;
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
int mdb_mid3l_insert( MDB_ID3L ids, MDB_ID3 *id )
|
||||
{
|
||||
unsigned x, i;
|
||||
|
||||
x = mdb_mid3l_search( ids, id->mid );
|
||||
|
||||
if( x < 1 ) {
|
||||
/* internal error */
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ( x <= ids[0].mid && ids[x].mid == id->mid ) {
|
||||
/* duplicate */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* insert id */
|
||||
ids[0].mid++;
|
||||
for (i=(unsigned)ids[0].mid; i>x; i--)
|
||||
ids[i] = ids[i-1];
|
||||
ids[x] = *id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* MDB_VL32 */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
/** @file midl.h
|
||||
* @brief LMDB ID List header file.
|
||||
*
|
||||
* This file was originally part of back-bdb but has been
|
||||
* modified for use in libmdb. Most of the macros defined
|
||||
* in this file are unused, just left over from the original.
|
||||
*
|
||||
* This file is only used internally in libmdb and its definitions
|
||||
* are not exposed publicly.
|
||||
*/
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2000-2015 The OpenLDAP Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_MIDL_H_
|
||||
#define _MDB_MIDL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup internal LMDB Internals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup idls ID List Management
|
||||
* @{
|
||||
*/
|
||||
/** A generic unsigned ID number. These were entryIDs in back-bdb.
|
||||
* Preferably it should have the same size as a pointer.
|
||||
*/
|
||||
#ifdef MDB_VL32
|
||||
typedef uint64_t MDB_ID;
|
||||
#else
|
||||
typedef size_t MDB_ID;
|
||||
#endif
|
||||
|
||||
/** An IDL is an ID List, a sorted array of IDs. The first
|
||||
* element of the array is a counter for how many actual
|
||||
* IDs are in the list. In the original back-bdb code, IDLs are
|
||||
* sorted in ascending order. For libmdb IDLs are sorted in
|
||||
* descending order.
|
||||
*/
|
||||
typedef MDB_ID *MDB_IDL;
|
||||
|
||||
/* IDL sizes - likely should be even bigger
|
||||
* limiting factors: sizeof(ID), thread stack size
|
||||
*/
|
||||
#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
|
||||
#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
|
||||
#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
|
||||
|
||||
#define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
|
||||
#define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
|
||||
|
||||
#define MDB_IDL_SIZEOF(ids) (((ids)[0]+1) * sizeof(MDB_ID))
|
||||
#define MDB_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
|
||||
#define MDB_IDL_CPY( dst, src ) (memcpy( dst, src, MDB_IDL_SIZEOF( src ) ))
|
||||
#define MDB_IDL_FIRST( ids ) ( (ids)[1] )
|
||||
#define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] )
|
||||
|
||||
/** Current max length of an #mdb_midl_alloc()ed IDL */
|
||||
#define MDB_IDL_ALLOCLEN( ids ) ( (ids)[-1] )
|
||||
|
||||
/** Append ID to IDL. The IDL must be big enough. */
|
||||
#define mdb_midl_xappend(idl, id) do { \
|
||||
MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \
|
||||
xidl[xlen] = (id); \
|
||||
} while (0)
|
||||
|
||||
/** Search for an ID in an IDL.
|
||||
* @param[in] ids The IDL to search.
|
||||
* @param[in] id The ID to search for.
|
||||
* @return The index of the first ID greater than or equal to \b id.
|
||||
*/
|
||||
unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id );
|
||||
|
||||
/** Allocate an IDL.
|
||||
* Allocates memory for an IDL of the given size.
|
||||
* @return IDL on success, NULL on failure.
|
||||
*/
|
||||
MDB_IDL mdb_midl_alloc(int num);
|
||||
|
||||
/** Free an IDL.
|
||||
* @param[in] ids The IDL to free.
|
||||
*/
|
||||
void mdb_midl_free(MDB_IDL ids);
|
||||
|
||||
/** Shrink an IDL.
|
||||
* Return the IDL to the default size if it has grown larger.
|
||||
* @param[in,out] idp Address of the IDL to shrink.
|
||||
*/
|
||||
void mdb_midl_shrink(MDB_IDL *idp);
|
||||
|
||||
/** Make room for num additional elements in an IDL.
|
||||
* @param[in,out] idp Address of the IDL.
|
||||
* @param[in] num Number of elements to make room for.
|
||||
* @return 0 on success, ENOMEM on failure.
|
||||
*/
|
||||
int mdb_midl_need(MDB_IDL *idp, unsigned num);
|
||||
|
||||
/** Append an ID onto an IDL.
|
||||
* @param[in,out] idp Address of the IDL to append to.
|
||||
* @param[in] id The ID to append.
|
||||
* @return 0 on success, ENOMEM if the IDL is too large.
|
||||
*/
|
||||
int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
|
||||
|
||||
/** Append an IDL onto an IDL.
|
||||
* @param[in,out] idp Address of the IDL to append to.
|
||||
* @param[in] app The IDL to append.
|
||||
* @return 0 on success, ENOMEM if the IDL is too large.
|
||||
*/
|
||||
int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
|
||||
|
||||
/** Append an ID range onto an IDL.
|
||||
* @param[in,out] idp Address of the IDL to append to.
|
||||
* @param[in] id The lowest ID to append.
|
||||
* @param[in] n Number of IDs to append.
|
||||
* @return 0 on success, ENOMEM if the IDL is too large.
|
||||
*/
|
||||
int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
|
||||
|
||||
/** Merge an IDL onto an IDL. The destination IDL must be big enough.
|
||||
* @param[in] idl The IDL to merge into.
|
||||
* @param[in] merge The IDL to merge.
|
||||
*/
|
||||
void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge );
|
||||
|
||||
/** Sort an IDL.
|
||||
* @param[in,out] ids The IDL to sort.
|
||||
*/
|
||||
void mdb_midl_sort( MDB_IDL ids );
|
||||
|
||||
/** An ID2 is an ID/pointer pair.
|
||||
*/
|
||||
typedef struct MDB_ID2 {
|
||||
MDB_ID mid; /**< The ID */
|
||||
void *mptr; /**< The pointer */
|
||||
} MDB_ID2;
|
||||
|
||||
/** An ID2L is an ID2 List, a sorted array of ID2s.
|
||||
* The first element's \b mid member is a count of how many actual
|
||||
* elements are in the array. The \b mptr member of the first element is unused.
|
||||
* The array is sorted in ascending order by \b mid.
|
||||
*/
|
||||
typedef MDB_ID2 *MDB_ID2L;
|
||||
|
||||
/** Search for an ID in an ID2L.
|
||||
* @param[in] ids The ID2L to search.
|
||||
* @param[in] id The ID to search for.
|
||||
* @return The index of the first ID2 whose \b mid member is greater than or equal to \b id.
|
||||
*/
|
||||
unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
|
||||
|
||||
|
||||
/** Insert an ID2 into a ID2L.
|
||||
* @param[in,out] ids The ID2L to insert into.
|
||||
* @param[in] id The ID2 to insert.
|
||||
* @return 0 on success, -1 if the ID was already present in the ID2L.
|
||||
*/
|
||||
int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
|
||||
|
||||
/** Append an ID2 into a ID2L.
|
||||
* @param[in,out] ids The ID2L to append into.
|
||||
* @param[in] id The ID2 to append.
|
||||
* @return 0 on success, -2 if the ID2L is too big.
|
||||
*/
|
||||
int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
|
||||
|
||||
#ifdef MDB_VL32
|
||||
typedef struct MDB_ID3 {
|
||||
MDB_ID mid; /**< The ID */
|
||||
void *mptr; /**< The pointer */
|
||||
unsigned int mcnt; /**< Number of pages */
|
||||
unsigned int mref; /**< Refcounter */
|
||||
} MDB_ID3;
|
||||
|
||||
typedef MDB_ID3 *MDB_ID3L;
|
||||
|
||||
unsigned mdb_mid3l_search( MDB_ID3L ids, MDB_ID id );
|
||||
int mdb_mid3l_insert( MDB_ID3L ids, MDB_ID3 *id );
|
||||
|
||||
#endif /* MDB_VL32 */
|
||||
/** @} */
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _MDB_MIDL_H_ */
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
/* mtest.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor, *cur2;
|
||||
MDB_cursor_op op;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[32] = "";
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
count = (rand()%384) + 64;
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
|
||||
for(i = 0;i<count;i++) {
|
||||
values[i] = rand()%1024;
|
||||
}
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_maxreaders(env, 1));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, NULL, 0, &dbi));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
for (i=0;i<count;i++) {
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
/* Set <data> in each iteration, since MDB_NOOVERWRITE may modify it */
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
|
||||
j++;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
}
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
j=0;
|
||||
key.mv_data = sval;
|
||||
for (i= count - 1; i > -1; i-= (rand()%5)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(sval, "%03x ", values[i]);
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor last\n");
|
||||
E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor last/prev\n");
|
||||
E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
E(mdb_cursor_get(cursor, &key, &data, MDB_PREV));
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
printf("Deleting with cursor\n");
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cur2));
|
||||
for (i=0; i<50; i++) {
|
||||
if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT)))
|
||||
break;
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
E(mdb_del(txn, dbi, &key, NULL));
|
||||
}
|
||||
|
||||
printf("Restarting cursor in txn\n");
|
||||
for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
|
||||
if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op)))
|
||||
break;
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
mdb_cursor_close(cur2);
|
||||
E(mdb_txn_commit(txn));
|
||||
|
||||
printf("Restarting cursor outside txn\n");
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
|
||||
if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op)))
|
||||
break;
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/* mtest2.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Just like mtest.c, but using a subDB instead of the main DB */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[32] = "";
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
count = (rand()%384) + 64;
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
|
||||
for(i = 0;i<count;i++) {
|
||||
values[i] = rand()%1024;
|
||||
}
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_maxreaders(env, 1));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 4));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id1", MDB_CREATE, &dbi));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
for (i=0;i<count;i++) {
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE)))
|
||||
j++;
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
j=0;
|
||||
key.mv_data = sval;
|
||||
for (i= count - 1; i > -1; i-= (rand()%5)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(sval, "%03x ", values[i]);
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/* mtest3.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for sorted duplicate DBs */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[32];
|
||||
char kval[sizeof(int)];
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
memset(sval, 0, sizeof(sval));
|
||||
|
||||
count = (rand()%384) + 64;
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
|
||||
for(i = 0;i<count;i++) {
|
||||
values[i] = rand()%1024;
|
||||
}
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 4));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
for (i=0;i<count;i++) {
|
||||
if (!(i & 0x0f))
|
||||
sprintf(kval, "%03x", values[i]);
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
|
||||
j++;
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
j=0;
|
||||
|
||||
for (i= count - 1; i > -1; i-= (rand()%5)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(kval, "%03x", values[i & ~0x0f]);
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
/* mtest4.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for sorted duplicate DBs with fixed-size keys */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[8];
|
||||
char kval[sizeof(int)];
|
||||
|
||||
memset(sval, 0, sizeof(sval));
|
||||
|
||||
count = 510;
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
|
||||
for(i = 0;i<count;i++) {
|
||||
values[i] = i*5;
|
||||
}
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 4));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
strcpy(kval, "001");
|
||||
for (i=0;i<count;i++) {
|
||||
sprintf(sval, "%07x", values[i]);
|
||||
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
|
||||
j++;
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
|
||||
/* there should be one full page of dups now.
|
||||
*/
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
/* test all 3 branches of split code:
|
||||
* 1: new key in lower half
|
||||
* 2: new key at split point
|
||||
* 3: new key in upper half
|
||||
*/
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
sprintf(sval, "%07x", values[3]+1);
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
(void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
sprintf(sval, "%07x", values[255]+1);
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
(void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
sprintf(sval, "%07x", values[500]+1);
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
(void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
|
||||
E(mdb_txn_commit(txn));
|
||||
|
||||
/* Try MDB_NEXT_MULTIPLE */
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT_MULTIPLE)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
j=0;
|
||||
|
||||
for (i= count - 1; i > -1; i-= (rand()%3)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(sval, "%07x", values[i]);
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/* mtest5.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for sorted duplicate DBs using cursor_put */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor;
|
||||
int count;
|
||||
int *values;
|
||||
char sval[32];
|
||||
char kval[sizeof(int)];
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
memset(sval, 0, sizeof(sval));
|
||||
|
||||
count = (rand()%384) + 64;
|
||||
values = (int *)malloc(count*sizeof(int));
|
||||
|
||||
for(i = 0;i<count;i++) {
|
||||
values[i] = rand()%1024;
|
||||
}
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 4));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
printf("Adding %d values\n", count);
|
||||
for (i=0;i<count;i++) {
|
||||
if (!(i & 0x0f))
|
||||
sprintf(kval, "%03x", values[i]);
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
if (RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA)))
|
||||
j++;
|
||||
}
|
||||
if (j) printf("%d duplicates skipped\n", j);
|
||||
mdb_cursor_close(cursor);
|
||||
E(mdb_txn_commit(txn));
|
||||
E(mdb_env_stat(env, &mst));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
j=0;
|
||||
|
||||
for (i= count - 1; i > -1; i-= (rand()%5)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(kval, "%03x", values[i & ~0x0f]);
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
/* mtest6.c - memory-mapped database tester/toy */
|
||||
/*
|
||||
* Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
/* Tests for DB splits and merges */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
|
||||
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
|
||||
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
|
||||
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
|
||||
|
||||
char dkbuf[1024];
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int i = 0, j = 0, rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data, sdata;
|
||||
MDB_txn *txn;
|
||||
MDB_stat mst;
|
||||
MDB_cursor *cursor;
|
||||
int count;
|
||||
int *values;
|
||||
long kval;
|
||||
char *sval;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
E(mdb_env_create(&env));
|
||||
E(mdb_env_set_mapsize(env, 10485760));
|
||||
E(mdb_env_set_maxdbs(env, 4));
|
||||
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
|
||||
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
E(mdb_stat(txn, dbi, &mst));
|
||||
|
||||
sval = calloc(1, mst.ms_psize / 4);
|
||||
key.mv_size = sizeof(long);
|
||||
key.mv_data = &kval;
|
||||
sdata.mv_size = mst.ms_psize / 4 - 30;
|
||||
sdata.mv_data = sval;
|
||||
|
||||
printf("Adding 12 values, should yield 3 splits\n");
|
||||
for (i=0;i<12;i++) {
|
||||
kval = i*5;
|
||||
sprintf(sval, "%08x", kval);
|
||||
data = sdata;
|
||||
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
|
||||
}
|
||||
printf("Adding 12 more values, should yield 3 splits\n");
|
||||
for (i=0;i<12;i++) {
|
||||
kval = i*5+4;
|
||||
sprintf(sval, "%08x", kval);
|
||||
data = sdata;
|
||||
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
|
||||
}
|
||||
printf("Adding 12 more values, should yield 3 splits\n");
|
||||
for (i=0;i<12;i++) {
|
||||
kval = i*5+1;
|
||||
sprintf(sval, "%08x", kval);
|
||||
data = sdata;
|
||||
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
|
||||
}
|
||||
E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST));
|
||||
|
||||
do {
|
||||
printf("key: %p %s, data: %p %.*s\n",
|
||||
key.mv_data, mdb_dkey(&key, dkbuf),
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
} while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0);
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_commit(txn);
|
||||
|
||||
#if 0
|
||||
j=0;
|
||||
|
||||
for (i= count - 1; i > -1; i-= (rand()%5)) {
|
||||
j++;
|
||||
txn=NULL;
|
||||
E(mdb_txn_begin(env, NULL, 0, &txn));
|
||||
sprintf(kval, "%03x", values[i & ~0x0f]);
|
||||
sprintf(sval, "%03x %d foo bar", values[i], values[i]);
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = kval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
|
||||
j--;
|
||||
mdb_txn_abort(txn);
|
||||
} else {
|
||||
E(mdb_txn_commit(txn));
|
||||
}
|
||||
}
|
||||
free(values);
|
||||
printf("Deleted %d values\n", j);
|
||||
|
||||
E(mdb_env_stat(env, &mst));
|
||||
E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
|
||||
E(mdb_cursor_open(txn, dbi, &cursor));
|
||||
printf("Cursor next\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
printf("Cursor prev\n");
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
|
||||
printf("key: %.*s, data: %.*s\n",
|
||||
(int) key.mv_size, (char *) key.mv_data,
|
||||
(int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
mdb_dbi_close(env, dbi);
|
||||
#endif
|
||||
mdb_env_close(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/* sample-bdb.txt - BerkeleyDB toy/sample
|
||||
*
|
||||
* Do a line-by-line comparison of this and sample-mdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <db.h>
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int rc;
|
||||
DB_ENV *env;
|
||||
DB *dbi;
|
||||
DBT key, data;
|
||||
DB_TXN *txn;
|
||||
DBC *cursor;
|
||||
char sval[32], kval[32];
|
||||
|
||||
/* Note: Most error checking omitted for simplicity */
|
||||
|
||||
#define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
|
||||
rc = db_env_create(&env, 0);
|
||||
rc = env->open(env, "./testdb", FLAGS, 0664);
|
||||
rc = db_create(&dbi, env, 0);
|
||||
rc = env->txn_begin(env, NULL, &txn, 0);
|
||||
rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
|
||||
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&data, 0, sizeof(DBT));
|
||||
key.size = sizeof(int);
|
||||
key.data = sval;
|
||||
data.size = sizeof(sval);
|
||||
data.data = sval;
|
||||
|
||||
sprintf(sval, "%03x %d foo bar", 32, 3141592);
|
||||
rc = dbi->put(dbi, txn, &key, &data, 0);
|
||||
rc = txn->commit(txn, 0);
|
||||
if (rc) {
|
||||
fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = env->txn_begin(env, NULL, &txn, 0);
|
||||
rc = dbi->cursor(dbi, txn, &cursor, 0);
|
||||
key.flags = DB_DBT_USERMEM;
|
||||
key.data = kval;
|
||||
key.ulen = sizeof(kval);
|
||||
data.flags = DB_DBT_USERMEM;
|
||||
data.data = sval;
|
||||
data.ulen = sizeof(sval);
|
||||
while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.data, (int) key.size, (char *) key.data,
|
||||
data.data, (int) data.size, (char *) data.data);
|
||||
}
|
||||
rc = cursor->c_close(cursor);
|
||||
rc = txn->abort(txn);
|
||||
leave:
|
||||
rc = dbi->close(dbi, 0);
|
||||
rc = env->close(env, 0);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/* sample-mdb.txt - MDB toy/sample
|
||||
*
|
||||
* Do a line-by-line comparison of this and sample-bdb.txt
|
||||
*/
|
||||
/*
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "lmdb.h"
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int rc;
|
||||
MDB_env *env;
|
||||
MDB_dbi dbi;
|
||||
MDB_val key, data;
|
||||
MDB_txn *txn;
|
||||
MDB_cursor *cursor;
|
||||
char sval[32];
|
||||
|
||||
/* Note: Most error checking omitted for simplicity */
|
||||
|
||||
rc = mdb_env_create(&env);
|
||||
rc = mdb_env_open(env, "./testdb", 0, 0664);
|
||||
rc = mdb_txn_begin(env, NULL, 0, &txn);
|
||||
rc = mdb_dbi_open(txn, NULL, 0, &dbi);
|
||||
|
||||
key.mv_size = sizeof(int);
|
||||
key.mv_data = sval;
|
||||
data.mv_size = sizeof(sval);
|
||||
data.mv_data = sval;
|
||||
|
||||
sprintf(sval, "%03x %d foo bar", 32, 3141592);
|
||||
rc = mdb_put(txn, dbi, &key, &data, 0);
|
||||
rc = mdb_txn_commit(txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
|
||||
rc = mdb_cursor_open(txn, dbi, &cursor);
|
||||
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.mv_data, (int) key.mv_size, (char *) key.mv_data,
|
||||
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
|
||||
}
|
||||
mdb_cursor_close(cursor);
|
||||
mdb_txn_abort(txn);
|
||||
leave:
|
||||
mdb_dbi_close(env, dbi);
|
||||
mdb_env_close(env);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<tagfile>
|
||||
<compound kind="page">
|
||||
<name>mdb_copy_1</name>
|
||||
<title>mdb_copy - environment copy tool</title>
|
||||
<filename>mdb_copy.1</filename>
|
||||
</compound>
|
||||
<compound kind="page">
|
||||
<name>mdb_dump_1</name>
|
||||
<title>mdb_dump - environment export tool</title>
|
||||
<filename>mdb_dump.1</filename>
|
||||
</compound>
|
||||
<compound kind="page">
|
||||
<name>mdb_load_1</name>
|
||||
<title>mdb_load - environment import tool</title>
|
||||
<filename>mdb_load.1</filename>
|
||||
</compound>
|
||||
<compound kind="page">
|
||||
<name>mdb_stat_1</name>
|
||||
<title>mdb_stat - environment status tool</title>
|
||||
<filename>mdb_stat.1</filename>
|
||||
</compound>
|
||||
</tagfile>
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/buildpack-deps:artful
|
||||
environment:
|
||||
- TESTDB: /tmp/test.db
|
||||
- TESTLOG: /tmp/test.log
|
||||
steps:
|
||||
- checkout
|
||||
- run: make all
|
||||
- run: ulimit -c unlimited && make check
|
||||
- run:
|
||||
command: |
|
||||
mkdir -p /tmp/artifacts
|
||||
mv -t /tmp/artifacts $TESTLOG $TESTDB core.*
|
||||
when: on_fail
|
||||
- store_artifacts:
|
||||
path: /tmp/artifacts
|
||||
destination: test-artifacts
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
BasedOnStyle: LLVM
|
||||
Standard: Cpp11
|
||||
ReflowComments: true
|
||||
35
src/contrib/db/libmdbx/.gitignore
vendored
35
src/contrib/db/libmdbx/.gitignore
vendored
|
|
@ -1,35 +0,0 @@
|
|||
*.[ao]
|
||||
*.bak
|
||||
*.exe
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.lo
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*[~#]
|
||||
.idea
|
||||
.le.ini
|
||||
.vs/
|
||||
cmake-build-*
|
||||
@*
|
||||
core
|
||||
mdbx_example
|
||||
libmdbx.creator.user
|
||||
mdbx_chk
|
||||
mdbx_copy
|
||||
mdbx_dump
|
||||
mdbx_load
|
||||
mdbx_stat
|
||||
mdbx_test
|
||||
test.log
|
||||
test/tmp.db
|
||||
test/tmp.db-lck
|
||||
tmp.db
|
||||
tmp.db-lck
|
||||
valgrind.*
|
||||
src/elements/version.c
|
||||
src/elements/config.h
|
||||
dist/
|
||||
*.tar*
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
language: c cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: precise
|
||||
env: CC=cc CXX=c++
|
||||
- os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
env: CC=clang CXX=clang++
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env: CC=gcc CXX=g++
|
||||
- os: linux
|
||||
dist: bionic
|
||||
compiler: clang
|
||||
env: CC=clang CXX=clang++
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env: CC=cc CXX=c++
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
env: CC=cc CXX=c++
|
||||
|
||||
script: >
|
||||
if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then
|
||||
git fetch --unshallow --tags --prune &&
|
||||
git submodule foreach --recursive git fetch --unshallow --tags --prune &&
|
||||
(if which clang-format-6.0 > /dev/null && make reformat && [[ -n $(git diff) ]];
|
||||
then
|
||||
echo "You must run 'make reformat' before submitting a pull request";
|
||||
echo "";
|
||||
git diff;
|
||||
exit -1;
|
||||
fi) &&
|
||||
make --keep-going all && MALLOC_CHECK_=7 MALLOC_PERTURB_=42 make --keep-going check
|
||||
else
|
||||
[ ! -s cov-int/scm_log.txt ] || cat cov-int/scm_log.txt;
|
||||
fi && sleep 3
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "M+W+heGGyRQJoBq2W0uqWVrpL4KBXmL0MFL7FSs7f9vmAaDyEgziUXeZRj3GOKzW4kTef3LpIeiu9SmvqSMoQivGGiomZShqPVl045o/OUgRCAT7Al1RLzEZ0efSHpIPf0PZ6byEf6GR2ML76OfuL6JxTVdnz8iVyO2sgLE1HbX1VeB+wgd/jfMeOBhCCXskfK6MLyZihfMYsiYZYSaV98ZDhDLSlzuuRIgzb0bMi8aL6AErs0WLW0NelRBeHkKPYfAUc85pdQHscgrJw6Rh/zT6+8BQ/q5f4IgWhiu4xoRg3Ngl7SNoedRQh93ADM3UG2iGl6HDFpVORaXcFWKAtuYY+kHQ0HB84BRYpQmeBuXNpltsfxQ3d1Q3u0RlE45zRvmr2+X1mFnkcNUAWISLPbsOUlriDQM8irGwRpho77/uYnRC00bJsHW//s6+uPf9zrAw1nI4f0y3PAWukGF/xs6HAI3FZPsuSSnx18Tj3Opgbc9Spop+V3hkhdiJoPGpNKTkFX4ZRXfkPgoRVJmtp4PpbpH0Ps/mCriKjMEfGGi0HcVCi0pEGLXiecdqJ5KPg5+22zNycEujQBJcNTKd9shN+R3glrbmhAxTEzGdGwxXXJ2ybwJ2PWJLMYZ7g98nLyX+uQPaA3BlsbYJHNeS5283/9pJsd9DzfHKsN2nFSc="
|
||||
|
||||
before_install:
|
||||
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
- ${CC} --version
|
||||
- ${CXX} --version
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ReOpen/libmdbx"
|
||||
version: 0.1
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: leo@yuriev.ru
|
||||
build_command_prepend: "git fetch --unshallow --tags --prune && make dist"
|
||||
build_command: "make MDBX_OPTIONS=-DMDBX_DEBUG=2 -C dist all"
|
||||
branch_pattern: coverity_scan
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
Contributors
|
||||
============
|
||||
|
||||
Alexey Naumov <alexey.naumov@gmail.com>
|
||||
Chris Mikkelson <cmikk@qwest.net>
|
||||
Claude Brisson <claude.brisson@gmail.com>
|
||||
David Barbour <dmbarbour@gmail.com>
|
||||
David Wilson <dw@botanicus.net>
|
||||
dreamsxin <dreamsxin@126.com>
|
||||
Hallvard Furuseth <hallvard@openldap.org>, <h.b.furuseth@usit.uio.no>
|
||||
Heiko Becker <heirecka@exherbo.org>
|
||||
Howard Chu <hyc@openldap.org>, <hyc@symas.com>
|
||||
Ignacio Casal Quinteiro <ignacio.casal@nice-software.com>
|
||||
James Rouzier <rouzier@gmail.com>
|
||||
Jean-Christophe DUBOIS <jcd@tribudubois.net>
|
||||
John Hewson <john@jahewson.com>
|
||||
Klaus Malorny <klaus.malorny@knipp.de>
|
||||
Kurt Zeilenga <kurt.zeilenga@isode.com>
|
||||
Leonid Yuriev <leo@yuriev.ru>, <lyuryev@ptsecurity.com>
|
||||
Lorenz Bauer <lmb@cloudflare.com>
|
||||
Luke Yeager <lyeager@nvidia.com>
|
||||
Martin Hedenfalk <martin@bzero.se>
|
||||
Ondrej Kuznik <ondrej.kuznik@acision.com>
|
||||
Orivej Desh <orivej@gmx.fr>
|
||||
Oskari Timperi <oskari.timperi@iki.fi>
|
||||
Pavel Medvedev <pmedvedev@gmail.com>
|
||||
Philipp Storz <philipp.storz@bareos.com>
|
||||
Quanah Gibson-Mount <quanah@openldap.org>
|
||||
Salvador Ortiz <sog@msg.com.mx>
|
||||
Sebastien Launay <sebastien@slaunay.fr>
|
||||
Vladimir Romanov <vromanov@gmail.com>
|
||||
Zano Foundation <crypto.sowle@gmail.com>
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
##
|
||||
## This is the minimal template for CMakeList.txt which could be used
|
||||
## to build libmdbx from the "amalgamated form" of libmdbx's source code.
|
||||
##
|
||||
## The amalgamated form is intended to embedding libmdbx in other projects
|
||||
## in cases when using as git-submodule is not acceptable or inconveniently.
|
||||
##
|
||||
## The amalgamated form could be generated from full git repository
|
||||
## on Linux just by `make dist`.
|
||||
##
|
||||
|
||||
##
|
||||
## Copyright 2019 Leonid Yuriev <leo@yuriev.ru>
|
||||
## and other libmdbx authors: please see AUTHORS file.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
##
|
||||
|
||||
##
|
||||
## libmdbx = { Revised and extended descendant of Symas LMDB. }
|
||||
## Please see README.md at https://github.com/leo-yuriev/libmdbx
|
||||
##
|
||||
## Libmdbx is superior to LMDB in terms of features and reliability,
|
||||
## not inferior in performance. libmdbx works on Linux, FreeBSD, MacOS X
|
||||
## and other systems compliant with POSIX.1-2008, but also support Windows
|
||||
## as a complementary platform.
|
||||
##
|
||||
## The next version is under active non-public development and will be
|
||||
## released as MithrilDB and libmithrildb for libraries & packages.
|
||||
## Admittedly mythical Mithril is resembling silver but being stronger and
|
||||
## lighter than steel. Therefore MithrilDB is rightly relevant name.
|
||||
##
|
||||
## MithrilDB will be radically different from libmdbx by the new database
|
||||
## format and API based on C++17, as well as the Apache 2.0 License.
|
||||
## The goal of this revolution is to provide a clearer and robust API,
|
||||
## add more features and new valuable properties of database.
|
||||
##
|
||||
## The Future will (be) Positive. Всё будет хорошо.
|
||||
##
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.8.2)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.9)
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
endif()
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||
cmake_policy(SET CMP0075 NEW)
|
||||
endif()
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif()
|
||||
|
||||
if(DEFINED PROJECT_NAME)
|
||||
set(SUBPROJECT ON)
|
||||
set(NOT_SUBPROJECT OFF)
|
||||
else()
|
||||
set(SUBPROJECT OFF)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
project(libmdbx C CXX)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif()
|
||||
|
||||
list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11)
|
||||
if(NOT HAS_C11 LESS 0)
|
||||
set(MDBX_C_STANDARD 11)
|
||||
else()
|
||||
set(MDBX_C_STANDARD 99)
|
||||
endif()
|
||||
message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx")
|
||||
|
||||
# not supported by this (minimal) script
|
||||
add_definitions(-DMDBX_AVOID_CRT=0)
|
||||
|
||||
# provide build timestamp
|
||||
string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
|
||||
add_definitions(-DMDBX_BUILD_TIMESTAMP="${MDBX_BUILD_TIMESTAMP}")
|
||||
|
||||
# provide compiler info
|
||||
execute_process(COMMAND sh -c "${CMAKE_C_COMPILER} --version | head -1"
|
||||
OUTPUT_VARIABLE MDBX_BUILD_COMPILER
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR NOT MDBX_BUILD_COMPILER)
|
||||
string(STRIP "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}" MDBX_BUILD_COMPILER)
|
||||
endif()
|
||||
add_definitions(-DMDBX_BUILD_COMPILER="${MDBX_BUILD_COMPILER}")
|
||||
|
||||
# provide cpu/arch-system pair
|
||||
if(CMAKE_C_COMPILER_TARGET)
|
||||
set(MDBX_BUILD_TARGET "${CMAKE_C_COMPILER_TARGET}")
|
||||
elseif(CMAKE_C_PLATFORM_ID AND NOT CMAKE_C_PLATFORM_ID STREQUAL CMAKE_SYSTEM_NAME)
|
||||
string(STRIP "${CMAKE_C_PLATFORM_ID}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_LIBRARY_ARCHITECTURE)
|
||||
string(STRIP "${CMAKE_LIBRARY_ARCHITECTURE}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_GENERATOR_PLATFORM AND NOT CMAKE_C_PLATFORM_ID STREQUAL CMAKE_SYSTEM_NAME)
|
||||
string(STRIP "${CMAKE_GENERATOR_PLATFORM}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_SYSTEM_ARCH)
|
||||
string(STRIP "${CMAKE_SYSTEM_ARCH}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
else()
|
||||
string(STRIP "${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
endif()
|
||||
add_definitions(-DMDBX_BUILD_TARGET="${MDBX_BUILD_TARGET}")
|
||||
|
||||
# provide build target-config
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
add_definitions(-DMDBX_BUILD_CONFIG="$<CONFIG>")
|
||||
else()
|
||||
add_definitions(-DMDBX_BUILD_CONFIG="${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
# provide build cflags
|
||||
set(MDBX_BUILD_FLAGS "")
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS})
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_DEFINES})
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
add_definitions(-DMDBX_BUILD_FLAGS_CONFIG="$<$<CONFIG:Debug>:${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_DEFINES_DEBUG}>$<$<CONFIG:Release>:${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_DEFINES_RELEASE}>$<$<CONFIG:RelWithDebInfo>:${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_DEFINES_RELWITHDEBINFO}>$<$<CONFIG:MinSizeRel>:${CMAKE_C_FLAGS_MINSIZEREL} ${CMAKE_C_DEFINES_MINSIZEREL}>")
|
||||
else()
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPERCASE)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_DEFINES_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
endif()
|
||||
list(REMOVE_DUPLICATES MDBX_BUILD_FLAGS)
|
||||
string(REPLACE ";" " " MDBX_BUILD_FLAGS "${MDBX_BUILD_FLAGS}")
|
||||
add_definitions(-DMDBX_BUILD_FLAGS="${MDBX_BUILD_FLAGS}")
|
||||
|
||||
# shared library
|
||||
if(NOT DEFINED MDBX_BUILD_SHARED_LIBRARY)
|
||||
if(DEFINED BUILD_SHARED_LIBS)
|
||||
option(MDBX_BUILD_SHARED_LIBRARY "Build libmdbx as shared library (DLL)" ${BUILD_SHARED_LIBS})
|
||||
else()
|
||||
option(MDBX_BUILD_SHARED_LIBRARY "Build libmdbx as shared library (DLL)" ON)
|
||||
endif()
|
||||
endif()
|
||||
if(MDBX_BUILD_SHARED_LIBRARY)
|
||||
add_library(mdbx SHARED mdbx.c mdbx.h)
|
||||
set_target_properties(mdbx PROPERTIES
|
||||
C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON
|
||||
PUBLIC_HEADER mdbx.h)
|
||||
target_compile_definitions(mdbx PRIVATE LIBMDBX_EXPORTS INTERFACE LIBMDBX_IMPORTS)
|
||||
if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
|
||||
set_target_properties(mdbx PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>)
|
||||
endif()
|
||||
target_link_libraries(mdbx PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(WIN32)
|
||||
target_link_libraries(mdbx PRIVATE ntdll.lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# static library used for tools, to avoid rpath/dll-path troubles
|
||||
add_library(mdbx-static STATIC EXCLUDE_FROM_ALL mdbx.c mdbx.h)
|
||||
set_target_properties(mdbx-static PROPERTIES
|
||||
C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON
|
||||
PUBLIC_HEADER mdbx.h)
|
||||
target_link_libraries(mdbx-static INTERFACE ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
|
||||
set_target_properties(mdbx-static PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>)
|
||||
endif()
|
||||
if(WIN32)
|
||||
target_link_libraries(mdbx-static INTERFACE ntdll.lib)
|
||||
endif()
|
||||
|
||||
# mdbx-tools
|
||||
foreach(TOOL mdbx_chk mdbx_copy mdbx_stat mdbx_dump mdbx_load)
|
||||
add_executable(${TOOL} ${TOOL}.c)
|
||||
set_target_properties(${TOOL} PROPERTIES
|
||||
C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON)
|
||||
if(DEFINED INTERPROCEDURAL_OPTIMIZATION)
|
||||
set_target_properties(${TOOL} PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>)
|
||||
endif()
|
||||
target_link_libraries(${TOOL} mdbx-static)
|
||||
endforeach()
|
||||
|
||||
cmake_policy(POP)
|
||||
|
|
@ -1,342 +0,0 @@
|
|||
##
|
||||
## Copyright 2019 Leonid Yuriev <leo@yuriev.ru>
|
||||
## and other libmdbx authors: please see AUTHORS file.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
##
|
||||
|
||||
##
|
||||
## libmdbx = { Revised and extended descendant of Symas LMDB. }
|
||||
## Please see README.md at https://github.com/leo-yuriev/libmdbx
|
||||
##
|
||||
## Libmdbx is superior to LMDB in terms of features and reliability,
|
||||
## not inferior in performance. libmdbx works on Linux, FreeBSD, MacOS X
|
||||
## and other systems compliant with POSIX.1-2008, but also support Windows
|
||||
## as a complementary platform.
|
||||
##
|
||||
## The next version is under active non-public development and will be
|
||||
## released as MithrilDB and libmithrildb for libraries & packages.
|
||||
## Admittedly mythical Mithril is resembling silver but being stronger and
|
||||
## lighter than steel. Therefore MithrilDB is rightly relevant name.
|
||||
##
|
||||
## MithrilDB will be radically different from libmdbx by the new database
|
||||
## format and API based on C++17, as well as the Apache 2.0 License.
|
||||
## The goal of this revolution is to provide a clearer and robust API,
|
||||
## add more features and new valuable properties of database.
|
||||
##
|
||||
## The Future will (be) Positive. Всё будет хорошо.
|
||||
##
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.8.2)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif()
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.12)
|
||||
cmake_policy(SET CMP0075 NEW)
|
||||
endif()
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.9)
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE)
|
||||
else()
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE FALSE)
|
||||
endif()
|
||||
|
||||
if(DEFINED PROJECT_NAME)
|
||||
set(SUBPROJECT ON)
|
||||
set(NOT_SUBPROJECT OFF)
|
||||
if(NOT DEFINED BUILD_TESTING)
|
||||
set(BUILD_TESTING OFF)
|
||||
endif()
|
||||
else()
|
||||
set(SUBPROJECT OFF)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
project(libmdbx C CXX)
|
||||
if(NOT DEFINED BUILD_TESTING)
|
||||
set(BUILD_TESTING ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif()
|
||||
|
||||
macro(add_mdbx_option NAME DESCRIPTION DEFAULT)
|
||||
list(APPEND MDBX_BUILD_OPTIONS ${NAME})
|
||||
if(NOT ${DEFAULT} STREQUAL "AUTO")
|
||||
option(${NAME} "${DESCRIPTION}" ${DEFAULT})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# only for compatibility testing
|
||||
# set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
if(NOT "$ENV{TEAMCITY_PROCESS_FLOW_ID}" STREQUAL "")
|
||||
set(CI TEAMCITY)
|
||||
message(STATUS "TeamCity CI")
|
||||
elseif(NOT "$ENV{TRAVIS}" STREQUAL "")
|
||||
set(CI TRAVIS)
|
||||
message(STATUS "Travis CI")
|
||||
elseif(NOT "$ENV{CIRCLECI}" STREQUAL "")
|
||||
set(CI CIRCLE)
|
||||
message(STATUS "Circle CI")
|
||||
elseif(NOT "$ENV{APPVEYOR}" STREQUAL "")
|
||||
set(CI APPVEYOR)
|
||||
message(STATUS "AppVeyor CI")
|
||||
elseif(NOT "$ENV{CI}" STREQUAL "")
|
||||
set(CI "$ENV{CI}")
|
||||
message(STATUS "Other CI (${CI})")
|
||||
else()
|
||||
message(STATUS "Assume No any CI environment")
|
||||
unset(CI)
|
||||
endif()
|
||||
|
||||
# output all mdbx-related targets in single directory
|
||||
if(NOT DEFINED MDBX_OUTPUT_DIR)
|
||||
set(MDBX_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
|
||||
set(CMAKE_PDB_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MDBX_OUTPUT_DIR})
|
||||
|
||||
include(CheckLibraryExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckCSourceRuns)
|
||||
include(CheckCXXSourceRuns)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(TestBigEndian)
|
||||
include(CheckFunctionExists)
|
||||
include(FindPackageMessage)
|
||||
include(CheckStructHasMember)
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION LESS 1900)
|
||||
message(SEND_ERROR "MSVC compiler ${MSVC_VERSION} is too old for building MDBX."
|
||||
" At least 'Microsoft Visual Studio 2015' is required.")
|
||||
endif()
|
||||
|
||||
# Set default build type to Release. This is to ease a User's life.
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif()
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPERCASE)
|
||||
|
||||
include(cmake/utils.cmake)
|
||||
include(cmake/compiler.cmake)
|
||||
include(cmake/profile.cmake)
|
||||
|
||||
find_program(ECHO echo)
|
||||
find_program(CAT cat)
|
||||
find_program(GIT git)
|
||||
find_program(LD ld)
|
||||
|
||||
# CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H)
|
||||
# CHECK_INCLUDE_FILES(sys/uio.h HAVE_SYS_UIO_H)
|
||||
# CHECK_INCLUDE_FILES(sys/stat.h HAVE_SYS_STAT_H)
|
||||
|
||||
CHECK_FUNCTION_EXISTS(pow NOT_NEED_LIBM)
|
||||
if(NOT_NEED_LIBM)
|
||||
set(LIB_MATH "")
|
||||
else()
|
||||
set(CMAKE_REQUIRED_LIBRARIES m)
|
||||
CHECK_FUNCTION_EXISTS(pow HAVE_LIBM)
|
||||
if(HAVE_LIBM)
|
||||
set(LIB_MATH m)
|
||||
else()
|
||||
message(FATAL_ERROR "No libm found for math support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(SUBPROJECT)
|
||||
if(NOT DEFINED BUILD_SHARED_LIBS)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" OFF)
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independed (PIC)" ON)
|
||||
endif()
|
||||
else()
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independed (PIC)" ON)
|
||||
if (CC_HAS_ARCH_NATIVE)
|
||||
option(BUILD_FOR_NATIVE_CPU "Generate code for the compiling machine CPU" OFF)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CONFIGURATION_TYPES OR NOT CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
||||
set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT ON)
|
||||
else()
|
||||
set(INTERPROCEDURAL_OPTIMIZATION_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE
|
||||
OR GCC_LTO_AVAILABLE OR MSVC_LTO_AVAILABLE OR CLANG_LTO_AVAILABLE)
|
||||
option(INTERPROCEDURAL_OPTIMIZATION "Enable interprocedural/LTO optimization" ${INTERPROCEDURAL_OPTIMIZATION_DEFAULT})
|
||||
endif()
|
||||
|
||||
if(INTERPROCEDURAL_OPTIMIZATION)
|
||||
if(GCC_LTO_AVAILABLE)
|
||||
set(LTO_ENABLED TRUE)
|
||||
set(CMAKE_AR ${CMAKE_GCC_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE)
|
||||
set(CMAKE_NM ${CMAKE_GCC_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE)
|
||||
set(CMAKE_RANLIB ${CMAKE_GCC_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE)
|
||||
message(STATUS "MDBX indulge Link-Time Optimization by GCC")
|
||||
elseif(CLANG_LTO_AVAILABLE)
|
||||
set(LTO_ENABLED TRUE)
|
||||
set(CMAKE_AR ${CMAKE_CLANG_AR} CACHE PATH "Path to ar program with LTO-plugin" FORCE)
|
||||
set(CMAKE_NM ${CMAKE_CLANG_NM} CACHE PATH "Path to nm program with LTO-plugin" FORCE)
|
||||
set(CMAKE_RANLIB ${CMAKE_CLANG_RANLIB} CACHE PATH "Path to ranlib program with LTO-plugin" FORCE)
|
||||
message(STATUS "MDBX indulge Link-Time Optimization by CLANG")
|
||||
elseif(MSVC_LTO_AVAILABLE)
|
||||
set(LTO_ENABLED TRUE)
|
||||
message(STATUS "MDBX indulge Link-Time Optimization by MSVC")
|
||||
elseif(CMAKE_INTERPROCEDURAL_OPTIMIZATION_AVAILABLE)
|
||||
message(STATUS "MDBX indulge Interprocedural Optimization by CMake")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
set(LTO_ENABLED TRUE)
|
||||
else()
|
||||
message(WARNING "Unable to engage interprocedural/LTO optimization.")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
set(LTO_ENABLED FALSE)
|
||||
endif()
|
||||
|
||||
find_program(VALGRIND valgrind)
|
||||
if(VALGRIND)
|
||||
# LY: cmake is ugly and nasty.
|
||||
# - therefore memcheck-options should be defined before including ctest;
|
||||
# - otherwise ctest may ignore it.
|
||||
set(MEMORYCHECK_SUPPRESSIONS_FILE
|
||||
"${PROJECT_SOURCE_DIR}/test/valgrind_suppress.txt"
|
||||
CACHE FILEPATH "Suppressions file for Valgrind" FORCE)
|
||||
set(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"--trace-children=yes --leak-check=full --track-origins=yes --error-exitcode=42 --error-markers=@ --errors-for-leak-kinds=definite --fair-sched=yes --suppressions=${MEMORYCHECK_SUPPRESSIONS_FILE}"
|
||||
CACHE STRING "Valgrind options" FORCE)
|
||||
set(VALGRIND_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS}" CACHE STRING "Valgrind options" FORCE)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Enable 'make tags' target.
|
||||
find_program(CTAGS ctags)
|
||||
if(CTAGS)
|
||||
add_custom_target(tags COMMAND ${CTAGS} -R -f tags
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
add_custom_target(ctags DEPENDS tags)
|
||||
endif(CTAGS)
|
||||
|
||||
#
|
||||
# Enable 'make reformat' target.
|
||||
find_program(CLANG_FORMAT
|
||||
NAMES clang-format-6.0 clang-format-5.0 clang-format-4.0
|
||||
clang-format-3.9 clang-format-3.8 clang-format-3.7 clang-format)
|
||||
if(CLANG_FORMAT AND UNIX)
|
||||
add_custom_target(reformat
|
||||
VERBATIM
|
||||
COMMAND
|
||||
git ls-files |
|
||||
grep -E \\.\(c|cxx|cc|cpp|h|hxx|hpp\)\(\\.in\)?\$ |
|
||||
xargs ${CLANG_FORMAT} -i --style=file
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
if(NOT "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
|
||||
add_custom_target(distclean)
|
||||
add_custom_command(TARGET distclean
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "${PROJECT_BINARY_DIR}"
|
||||
COMMENT "Removing the build directory and its content")
|
||||
elseif(IS_DIRECTORY .git AND GIT)
|
||||
add_custom_target(distclean)
|
||||
add_custom_command(TARGET distclean
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMAND ${GIT} submodule foreach --recursive git clean -f -X -d
|
||||
COMMAND ${GIT} clean -f -X -d
|
||||
COMMENT "Removing all build files from the source directory")
|
||||
endif()
|
||||
|
||||
setup_compile_flags()
|
||||
endif(SUBPROJECT)
|
||||
|
||||
list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11)
|
||||
if(NOT HAS_C11 LESS 0)
|
||||
set(MDBX_C_STANDARD 11)
|
||||
else()
|
||||
set(MDBX_C_STANDARD 99)
|
||||
endif()
|
||||
message(STATUS "Use C${MDBX_C_STANDARD} for libmdbx")
|
||||
|
||||
##############################################################################
|
||||
##############################################################################
|
||||
#
|
||||
# #### ##### ##### # #### # # ####
|
||||
# # # # # # # # # ## # #
|
||||
# # # # # # # # # # # # ####
|
||||
# # # ##### # # # # # # # #
|
||||
# # # # # # # # # ## # #
|
||||
# #### # # # #### # # ####
|
||||
#
|
||||
|
||||
set(MDBX_BUILD_OPTIONS ENABLE_ASAN MDBX_USE_VALGRIND ENABLE_GPROF ENABLE_GCOV)
|
||||
add_mdbx_option(MDBX_BUILD_SHARED_LIBRARY "Build libmdbx as shared library (DLL)" ${BUILD_SHARED_LIBS})
|
||||
add_mdbx_option(MDBX_ALLOY_BUILD "Build MDBX library as single object file" ON)
|
||||
add_mdbx_option(MDBX_TXN_CHECKOWNER "Checking transaction matches the calling thread inside libmdbx's API" ON)
|
||||
add_mdbx_option(MDBX_TXN_CHECKPID "Paranoid checking PID inside libmdbx's API" AUTO)
|
||||
mark_as_advanced(MDBX_TXN_CHECKPID)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
add_mdbx_option(MDBX_DISABLE_GNU_SOURCE "Don't use nonstandard GNU/Linux extension functions" OFF)
|
||||
mark_as_advanced(MDBX_DISABLE_GNU_SOURCE)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
add_mdbx_option(MDBX_OSX_SPEED_INSTEADOF_DURABILITY "Disable use fcntl(F_FULLFSYNC) in favor of speed" OFF)
|
||||
mark_as_advanced(MDBX_OSX_SPEED_INSTEADOF_DURABILITY)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
add_mdbx_option(MDBX_AVOID_CRT "Avoid dependence from MSVC CRT" ${NOT_SUBPROJECT})
|
||||
if(NOT MDBX_BUILD_SHARED_LIBRARY)
|
||||
add_mdbx_option(MDBX_CONFIG_MANUAL_TLS_CALLBACK
|
||||
"Provide mdbx_dll_handler() for manual initialization" OFF)
|
||||
mark_as_advanced(MDBX_CONFIG_MANUAL_TLS_CALLBACK)
|
||||
endif()
|
||||
else()
|
||||
add_mdbx_option(MDBX_USE_ROBUST "Use POSIX.1-2008 robust mutexes" AUTO)
|
||||
mark_as_advanced(MDBX_USE_ROBUST)
|
||||
add_mdbx_option(MDBX_USE_OFDLOCKS "Use Open file description locks (aka OFD locks, non-POSIX)" AUTO)
|
||||
mark_as_advanced(MDBX_USE_OFDLOCKS)
|
||||
endif()
|
||||
option(MDBX_ENABLE_TESTS "Build MDBX tests." ${BUILD_TESTING})
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
add_subdirectory(src)
|
||||
if(MDBX_ENABLE_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
set(PACKAGE "libmdbx")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${MDBX_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${MDBX_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${MDBX_VERSION_RELEASE})
|
||||
set(CPACK_PACKAGE_VERSION_COMMIT ${MDBX_VERSION_REVISION})
|
||||
set(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}.${CPACK_PACKAGE_VERSION_COMMIT}")
|
||||
message(STATUS "libmdbx package version is ${PACKAGE_VERSION}")
|
||||
|
||||
cmake_policy(POP)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted only as authorized by the OpenLDAP
|
||||
Public License.
|
||||
|
||||
A copy of this license is available in the file LICENSE in the
|
||||
top-level directory of the distribution or, alternatively, at
|
||||
<http://www.OpenLDAP.org/license.html>.
|
||||
|
||||
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
|
||||
|
||||
Individual files and/or contributed packages may be copyright by
|
||||
other parties and/or subject to additional restrictions.
|
||||
|
||||
This work also contains materials derived from public sources.
|
||||
|
||||
Additional information about OpenLDAP can be obtained at
|
||||
<http://www.openldap.org/>.
|
||||
|
|
@ -1,362 +0,0 @@
|
|||
# This makefile is for GNU Make, and nowadays provided
|
||||
# just for compatibility and preservation of traditions.
|
||||
# Please use CMake in case of any difficulties or problems.
|
||||
#
|
||||
# Preprocessor macros (for MDBX_OPTIONS) of interest...
|
||||
# Note that the defaults should already be correct for most platforms;
|
||||
# you should not need to change any of these. Read their descriptions
|
||||
# in README and source code if you do. There may be other macros of interest.
|
||||
SHELL := /bin/bash
|
||||
|
||||
# install sandbox
|
||||
SANDBOX ?=
|
||||
|
||||
# install prefixes (inside sandbox)
|
||||
prefix ?= /usr/local
|
||||
mandir ?= $(prefix)/man
|
||||
|
||||
# lib/bin suffix for multiarch/biarch, e.g. '.x86_64'
|
||||
suffix ?=
|
||||
|
||||
CC ?= gcc
|
||||
LD ?= ld
|
||||
MDBX_OPTIONS ?= -DNDEBUG=1
|
||||
CFLAGS ?= -Os -g3 -Wall -Werror -Wextra -Wpedantic -ffunction-sections -fPIC -fvisibility=hidden -std=gnu11 -pthread -Wno-tautological-compare
|
||||
|
||||
# LY: '--no-as-needed,-lrt' for ability to built with modern glibc, but then run with the old
|
||||
LDFLAGS ?= $(shell $(LD) --help 2>/dev/null | grep -q -- --gc-sections && echo '-Wl,--gc-sections,-z,relro,-O1')$(shell $(LD) --help 2>/dev/null | grep -q -- -dead_strip && echo '-Wl,-dead_strip')
|
||||
EXE_LDFLAGS ?= -pthread
|
||||
|
||||
################################################################################
|
||||
|
||||
UNAME := $(shell uname -s 2>/dev/null || echo Unknown)
|
||||
define uname2sosuffix
|
||||
case "$(UNAME)" in
|
||||
Darwin*|Mach*) echo dylib;;
|
||||
CYGWIN*|MINGW*|MSYS*|Windows*) echo dll;;
|
||||
*) echo so;;
|
||||
esac
|
||||
endef
|
||||
SO_SUFFIX := $(shell $(uname2sosuffix))
|
||||
|
||||
HEADERS := mdbx.h
|
||||
LIBRARIES := libmdbx.a libmdbx.$(SO_SUFFIX)
|
||||
TOOLS := mdbx_stat mdbx_copy mdbx_dump mdbx_load mdbx_chk
|
||||
MANPAGES := mdbx_stat.1 mdbx_copy.1 mdbx_dump.1 mdbx_load.1 mdbx_chk.1
|
||||
|
||||
.PHONY: mdbx all install clean test dist check
|
||||
|
||||
all: $(LIBRARIES) $(TOOLS)
|
||||
|
||||
mdbx: libmdbx.a libmdbx.$(SO_SUFFIX)
|
||||
|
||||
tools: $(TOOLS)
|
||||
|
||||
strip: all
|
||||
strip libmdbx.$(SO_SUFFIX) $(TOOLS)
|
||||
|
||||
clean:
|
||||
rm -rf $(TOOLS) mdbx_test @* *.[ao] *.[ls]o *~ tmp.db/* \
|
||||
*.gcov *.log *.err src/*.o test/*.o mdbx_example dist \
|
||||
config.h src/elements/config.h src/elements/version.c *.tar*
|
||||
|
||||
libmdbx.a: mdbx-static.o
|
||||
$(AR) rs $@ $?
|
||||
|
||||
libmdbx.$(SO_SUFFIX): mdbx-dylib.o
|
||||
$(CC) $(CFLAGS) $^ -pthread -shared $(LDFLAGS) -o $@
|
||||
|
||||
#> dist-cutoff-begin
|
||||
ifeq ($(wildcard mdbx.c),mdbx.c)
|
||||
#< dist-cutoff-end
|
||||
|
||||
################################################################################
|
||||
# Amalgamated source code, i.e. distributed after `make dists`
|
||||
MAN_SRCDIR := man1/
|
||||
|
||||
config.h: mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
(echo '#define MDBX_BUILD_TIMESTAMP "$(shell date +%Y-%m-%dT%H:%M:%S%z)"' \
|
||||
&& echo '#define MDBX_BUILD_FLAGS "$(CFLAGS) $(LDFLAGS)"' \
|
||||
&& echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"' \
|
||||
&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || echo 'Please use GCC or CLANG compatible compiler')"' \
|
||||
) > $@
|
||||
|
||||
mdbx-dylib.o: config.h mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c mdbx.c -o $@
|
||||
|
||||
mdbx-static.o: config.h mdbx.c $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c mdbx.c -o $@
|
||||
|
||||
mdbx_%: mdbx_%.c libmdbx.a
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' $^ $(EXE_LDFLAGS) -o $@
|
||||
|
||||
#> dist-cutoff-begin
|
||||
else
|
||||
################################################################################
|
||||
# Plain (non-amalgamated) sources with test
|
||||
|
||||
define uname2osal
|
||||
case "$(UNAME)" in
|
||||
CYGWIN*|MINGW*|MSYS*|Windows*) echo windows;;
|
||||
*) echo unix;;
|
||||
esac
|
||||
endef
|
||||
|
||||
define uname2titer
|
||||
case "$(UNAME)" in
|
||||
Darwin*|Mach*) echo 2;;
|
||||
*) echo 12;;
|
||||
esac
|
||||
endef
|
||||
|
||||
DIST_EXTRA := LICENSE README.md CMakeLists.txt GNUmakefile $(addprefix man1/, $(MANPAGES))
|
||||
DIST_SRC := mdbx.h mdbx.c $(addsuffix .c, $(TOOLS))
|
||||
|
||||
TEST_DB ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.db
|
||||
TEST_LOG ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.log
|
||||
TEST_OSAL := $(shell $(uname2osal))
|
||||
TEST_ITER := $(shell $(uname2titer))
|
||||
TEST_SRC := test/osal-$(TEST_OSAL).cc $(filter-out $(wildcard test/osal-*.cc), $(wildcard test/*.cc))
|
||||
TEST_INC := $(wildcard test/*.h)
|
||||
TEST_OBJ := $(patsubst %.cc,%.o,$(TEST_SRC))
|
||||
CXX ?= g++
|
||||
CXXSTD ?= $(shell $(CXX) -std=c++27 -c test/test.cc -o /dev/null 2>/dev/null && echo -std=c++17 || echo -std=c++11)
|
||||
CXXFLAGS := $(CXXSTD) $(filter-out -std=gnu11,$(CFLAGS))
|
||||
|
||||
MAN_SRCDIR := src/man1/
|
||||
ALLOY_DEPS := $(wildcard src/elements/*)
|
||||
MDBX_VERSION_GIT = ${shell set -o pipefail; git describe --tags | sed -n 's|^v*\([0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\)\(.*\)|\1|p' || echo 'Please fetch tags and/or install latest git version'}
|
||||
MDBX_GIT_TIMESTAMP = $(shell git show --no-patch --format=%cI HEAD || echo 'Please install latest get version')
|
||||
MDBX_GIT_DESCRIBE = $(shell git describe --tags --long --dirty=-dirty || echo 'Please fetch tags and/or install latest git version')
|
||||
MDBX_VERSION_SUFFIX = $(shell set -o pipefail; echo -n '$(MDBX_GIT_DESCRIBE)' | tr -c -s '[a-zA-Z0-9]' _)
|
||||
MDBX_BUILD_SOURCERY = $(shell set -o pipefail; $(MAKE) -s src/elements/version.c && (openssl dgst -r -sha256 src/elements/version.c || sha256sum src/elements/version.c || shasum -a 256 src/elements/version.c) 2>/dev/null | cut -d ' ' -f 1 || echo 'Please install openssl or sha256sum or shasum')_$(MDBX_VERSION_SUFFIX)
|
||||
|
||||
test check: all mdbx_example mdbx_test
|
||||
rm -f $(TEST_DB) $(TEST_LOG) && (set -o pipefail; \
|
||||
(./mdbx_test --progress --console=no --repeat=$(TEST_ITER) --pathname=$(TEST_DB) --dont-cleanup-after basic && \
|
||||
./mdbx_test --mode=-writemap,-lifo --progress --console=no --repeat=1 --pathname=$(TEST_DB) --dont-cleanup-after basic) \
|
||||
| tee -a $(TEST_LOG) | tail -n 42) \
|
||||
&& ./mdbx_chk -vvn $(TEST_DB) && ./mdbx_chk -vvn $(TEST_DB)-copy
|
||||
|
||||
mdbx_example: mdbx.h example/example-mdbx.c libmdbx.$(SO_SUFFIX)
|
||||
$(CC) $(CFLAGS) -I. example/example-mdbx.c ./libmdbx.$(SO_SUFFIX) -o $@
|
||||
|
||||
check-singleprocess: all mdbx_test
|
||||
rm -f $(TEST_DB) $(TEST_LOG) && (set -o pipefail; \
|
||||
(./mdbx_test --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after --hill && \
|
||||
./mdbx_test --progress --console=no --repeat=2 --pathname=$(TEST_DB) --dont-cleanup-before --dont-cleanup-after --copy && \
|
||||
./mdbx_test --mode=-writemap,-lifo --progress --console=no --repeat=42 --pathname=$(TEST_DB) --dont-cleanup-after --nested) \
|
||||
| tee -a $(TEST_LOG) | tail -n 42) \
|
||||
&& ./mdbx_chk -vvn $(TEST_DB) && ./mdbx_chk -vvn $(TEST_DB)-copy
|
||||
|
||||
check-fault: all mdbx_test
|
||||
rm -f $(TEST_DB) $(TEST_LOG) && (set -o pipefail; ./mdbx_test --progress --console=no --pathname=$(TEST_DB) --inject-writefault=42 --dump-config --dont-cleanup-after basic | tee -a $(TEST_LOG) | tail -n 42) \
|
||||
; ./mdbx_chk -vvnw $(TEST_DB) && ([ ! -e $(TEST_DB)-copy ] || ./mdbx_chk -vvn $(TEST_DB)-copy)
|
||||
|
||||
VALGRIND=valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt
|
||||
memcheck check-valgrind: all mdbx_test
|
||||
@echo "$(MDBX_OPTIONS)" | grep -q MDBX_USE_VALGRIND || echo "WARNING: Please build libmdbx with -DMDBX_USE_VALGRIND to avoid false-positives from Valgrind !!!" >&2
|
||||
rm -f valgrind-*.log $(TEST_DB) $(TEST_LOG) && (set -o pipefail; \
|
||||
($(VALGRIND) ./mdbx_test --mode=-writemap,-lifo --progress --console=no --repeat=4 --pathname=$(TEST_DB) --dont-cleanup-after basic && \
|
||||
$(VALGRIND) ./mdbx_test --progress --console=no --pathname=$(TEST_DB) --dont-cleanup-before --dont-cleanup-after --copy && \
|
||||
$(VALGRIND) ./mdbx_test --progress --console=no --repeat=2 --pathname=$(TEST_DB) --dont-cleanup-after basic) \
|
||||
| tee -a $(TEST_LOG) | tail -n 42) \
|
||||
&& $(VALGRIND) ./mdbx_chk -vvn $(TEST_DB) && ./mdbx_chk -vvn $(TEST_DB)-copy
|
||||
|
||||
define test-rule
|
||||
$(patsubst %.cc,%.o,$(1)): $(1) $(TEST_INC) mdbx.h $(lastword $(MAKEFILE_LIST))
|
||||
$(CXX) $(CXXFLAGS) $(MDBX_OPTIONS) -c $(1) -o $$@
|
||||
|
||||
endef
|
||||
$(foreach file,$(TEST_SRC),$(eval $(call test-rule,$(file))))
|
||||
|
||||
mdbx_%: src/tools/mdbx_%.c libmdbx.a
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' $^ $(EXE_LDFLAGS) -o $@
|
||||
|
||||
mdbx_test: $(TEST_OBJ) libmdbx.$(SO_SUFFIX)
|
||||
$(CXX) $(CXXFLAGS) $(TEST_OBJ) -Wl,-rpath . -L . -l mdbx $(EXE_LDFLAGS) -o $@
|
||||
|
||||
git_DIR := $(shell if [ -d .git ]; then echo .git; elif [ -s .git -a -f .git ]; then grep '^gitdir: ' .git | cut -d ':' -f 2; else echo "Please use libmdbx as a git-submodule or the amalgamated source code" >&2 && echo git_directory; fi)
|
||||
|
||||
src/elements/version.c: src/elements/version.c.in $(lastword $(MAKEFILE_LIST)) $(git_DIR)/HEAD $(git_DIR)/index $(git_DIR)/refs/tags
|
||||
sed \
|
||||
-e "s|@MDBX_GIT_TIMESTAMP@|$(MDBX_GIT_TIMESTAMP)|" \
|
||||
-e "s|@MDBX_GIT_TREE@|$(shell git show --no-patch --format=%T HEAD || echo 'Please install latest get version')|" \
|
||||
-e "s|@MDBX_GIT_COMMIT@|$(shell git show --no-patch --format=%H HEAD || echo 'Please install latest get version')|" \
|
||||
-e "s|@MDBX_GIT_DESCRIBE@|$(MDBX_GIT_DESCRIBE)|" \
|
||||
-e "s|\$${MDBX_VERSION_MAJOR}|$(shell echo '$(MDBX_VERSION_GIT)' | cut -d . -f 1)|" \
|
||||
-e "s|\$${MDBX_VERSION_MINOR}|$(shell echo '$(MDBX_VERSION_GIT)' | cut -d . -f 2)|" \
|
||||
-e "s|\$${MDBX_VERSION_RELEASE}|$(shell echo '$(MDBX_VERSION_GIT)' | cut -d . -f 3)|" \
|
||||
-e "s|\$${MDBX_VERSION_REVISION}|$(shell git rev-list --count --no-merges HEAD || echo 'Please fetch tags and/or install latest git version')|" \
|
||||
src/elements/version.c.in > $@
|
||||
|
||||
src/elements/config.h: src/elements/version.c $(lastword $(MAKEFILE_LIST))
|
||||
(echo '#define MDBX_BUILD_TIMESTAMP "$(shell date +%Y-%m-%dT%H:%M:%S%z)"' \
|
||||
&& echo '#define MDBX_BUILD_FLAGS "$(CFLAGS) $(LDFLAGS)"' \
|
||||
&& echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"' \
|
||||
&& echo '#define MDBX_BUILD_TARGET "$(shell set -o pipefail; LC_ALL=C $(CC) -v 2>&1 | grep -i '^Target:' | cut -d ' ' -f 2- || echo 'Please use GCC or CLANG compatible compiler')"' \
|
||||
&& echo '#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)' \
|
||||
) > $@
|
||||
|
||||
mdbx-dylib.o: src/elements/config.h src/elements/version.c src/alloy.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -DLIBMDBX_EXPORTS=1 -c src/alloy.c -o $@
|
||||
|
||||
mdbx-static.o: src/elements/config.h src/elements/version.c src/alloy.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
|
||||
$(CC) $(CFLAGS) $(MDBX_OPTIONS) '-DMDBX_CONFIG_H="config.h"' -ULIBMDBX_EXPORTS -c src/alloy.c -o $@
|
||||
|
||||
.PHONY: dist
|
||||
dist: libmdbx-sources-$(MDBX_VERSION_SUFFIX).tar.gz $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
libmdbx-sources-$(MDBX_VERSION_SUFFIX).tar.gz: $(addprefix dist/, $(DIST_SRC) $(DIST_EXTRA)) $(addprefix dist/man1/,$(MANPAGES))
|
||||
tar -c -a -f $@ --owner=0 --group=0 -C dist $(DIST_SRC) $(DIST_EXTRA) \
|
||||
&& rm dist/@tmp-shared_internals.inc
|
||||
|
||||
dist/mdbx.h: mdbx.h src/elements/version.c $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && cp $< $@
|
||||
|
||||
dist/GNUmakefile: GNUmakefile
|
||||
mkdir -p dist && sed -e '/^#> dist-cutoff-begin/,/^#< dist-cutoff-end/d' $< > $@
|
||||
|
||||
dist/@tmp-shared_internals.inc: src/elements/version.c $(ALLOY_DEPS) $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && sed \
|
||||
-e 's|#pragma once|#define MDBX_ALLOY 1\n#define MDBX_BUILD_SOURCERY $(MDBX_BUILD_SOURCERY)|' \
|
||||
-e 's|#include "../../mdbx.h"|@INCLUDE "mdbx.h"|' \
|
||||
-e '/#include "defs.h"/r src/elements/defs.h' \
|
||||
-e '/#include "osal.h"/r src/elements/osal.h' \
|
||||
src/elements/internals.h > $@
|
||||
|
||||
dist/mdbx.c: dist/@tmp-shared_internals.inc $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && (cat dist/@tmp-shared_internals.inc \
|
||||
&& cat src/elements/core.c src/elements/osal.c src/elements/version.c \
|
||||
&& echo '#if defined(_WIN32) || defined(_WIN64)' \
|
||||
&& cat src/elements/lck-windows.c && echo '#else /* LCK-implementation */' \
|
||||
&& cat src/elements/lck-posix.c && echo '#endif /* LCK-implementation */' \
|
||||
) | grep -v -e '#include "' -e '#pragma once' | sed 's|@INCLUDE|#include|' > $@
|
||||
|
||||
define dist-tool-rule
|
||||
dist/$(1).c: src/tools/$(1).c src/tools/wingetopt.h src/tools/wingetopt.c \
|
||||
dist/@tmp-shared_internals.inc $(lastword $(MAKEFILE_LIST))
|
||||
mkdir -p dist && sed \
|
||||
-e '/#include "..\/elements\/internals.h"/r dist/@tmp-shared_internals.inc' \
|
||||
-e '/#include "wingetopt.h"/r src/tools/wingetopt.c' \
|
||||
src/tools/$(1).c \
|
||||
| grep -v -e '#include "' -e '#pragma once' -e '#define MDBX_ALLOY' \
|
||||
| sed 's|@INCLUDE|#include|' > $$@
|
||||
|
||||
endef
|
||||
$(foreach file,$(TOOLS),$(eval $(call dist-tool-rule,$(file))))
|
||||
|
||||
dist/man1/mdbx_%.1: src/man1/mdbx_%.1
|
||||
mkdir -p dist/man1/ && cp $< $@
|
||||
dist/LICENSE: LICENSE
|
||||
mkdir -p dist/man1/ && cp $< $@
|
||||
dist/README.md: README.md
|
||||
mkdir -p dist/man1/ && cp $< $@
|
||||
dist/CMakeLists.txt: CMakeLists.dist-minimal
|
||||
mkdir -p dist/man1/ && cp $< $@
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Cross-compilation simple test
|
||||
|
||||
CROSS_LIST = mips-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc powerpc-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc \
|
||||
sh4-linux-gnu-gcc mips64-linux-gnuabi64-gcc
|
||||
|
||||
# hppa-linux-gnu-gcc - don't supported by current qemu release
|
||||
# s390x-linux-gnu-gcc - qemu troubles (hang/abort)
|
||||
# sparc64-linux-gnu-gcc - qemu troubles (fcntl for F_SETLK/F_GETLK)
|
||||
# alpha-linux-gnu-gcc - qemu (or gcc) troubles (coredump)
|
||||
|
||||
CROSS_LIST_NOQEMU = hppa-linux-gnu-gcc s390x-linux-gnu-gcc \
|
||||
sparc64-linux-gnu-gcc alpha-linux-gnu-gcc
|
||||
|
||||
cross-gcc:
|
||||
@echo "CORRESPONDING CROSS-COMPILERs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu g++-sparc64-linux-gnu"
|
||||
@for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \
|
||||
echo "===================== $$CC"; \
|
||||
$(MAKE) clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) all || exit $$?; \
|
||||
done
|
||||
|
||||
# Unfortunately qemu don't provide robust support for futexes.
|
||||
# Therefore it is impossible to run full multi-process tests.
|
||||
cross-qemu:
|
||||
@echo "CORRESPONDING CROSS-COMPILERs AND QEMUs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: "
|
||||
@echo " 1) apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu g++-sparc64-linux-gnu"
|
||||
@echo " 2) apt install binfmt-support qemu-user-static qemu-user qemu-system-arm qemu-system-mips qemu-system-misc qemu-system-ppc qemu-system-sparc"
|
||||
@for CC in $(CROSS_LIST); do \
|
||||
echo "===================== $$CC + qemu"; \
|
||||
$(MAKE) clean && \
|
||||
CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_OPTIONS)" \
|
||||
$(MAKE) check-singleprocess || exit $$?; \
|
||||
done
|
||||
|
||||
#< dist-cutoff-end
|
||||
install: $(LIBRARIES) $(TOOLS) $(HEADERS)
|
||||
mkdir -p $(SANDBOX)$(prefix)/bin$(suffix) \
|
||||
&& cp -t $(SANDBOX)$(prefix)/bin$(suffix) $(TOOLS) && \
|
||||
mkdir -p $(SANDBOX)$(prefix)/lib$(suffix) \
|
||||
&& cp -t $(SANDBOX)$(prefix)/lib$(suffix) $(LIBRARIES) && \
|
||||
mkdir -p $(SANDBOX)$(prefix)/include \
|
||||
&& cp -t $(SANDBOX)$(prefix)/include $(HEADERS) && \
|
||||
mkdir -p $(SANDBOX)$(mandir)/man1 \
|
||||
&& cp -t $(SANDBOX)$(mandir)/man1 $(addprefix $(MAN_SRCDIR), $(MANPAGES))
|
||||
|
||||
################################################################################
|
||||
# Benchmarking by ioarena
|
||||
|
||||
IOARENA ?= $(shell \
|
||||
(test -x ../ioarena/@BUILD/src/ioarena && echo ../ioarena/@BUILD/src/ioarena) || \
|
||||
(test -x ../../@BUILD/src/ioarena && echo ../../@BUILD/src/ioarena) || \
|
||||
(test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena)
|
||||
NN ?= 25000000
|
||||
|
||||
ifneq ($(wildcard $(IOARENA)),)
|
||||
|
||||
.PHONY: bench clean-bench re-bench
|
||||
|
||||
clean-bench:
|
||||
rm -rf bench-*.txt _ioarena/*
|
||||
|
||||
re-bench: clean-bench bench
|
||||
|
||||
define bench-rule
|
||||
bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST))
|
||||
LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
|
||||
$(IOARENA) -D $(1) -B crud -m nosync -n $(2) \
|
||||
| tee $$@ | grep throughput && \
|
||||
LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
|
||||
$(IOARENA) -D $(1) -B get,iterate -m sync -r 4 -n $(2) \
|
||||
| tee -a $$@ | grep throughput \
|
||||
|| mv -f $$@ $$@.error
|
||||
|
||||
endef
|
||||
|
||||
$(eval $(call bench-rule,mdbx,$(NN),libmdbx.$(SO_SUFFIX)))
|
||||
|
||||
$(eval $(call bench-rule,sophia,$(NN)))
|
||||
$(eval $(call bench-rule,leveldb,$(NN)))
|
||||
$(eval $(call bench-rule,rocksdb,$(NN)))
|
||||
$(eval $(call bench-rule,wiredtiger,$(NN)))
|
||||
$(eval $(call bench-rule,forestdb,$(NN)))
|
||||
$(eval $(call bench-rule,lmdb,$(NN)))
|
||||
$(eval $(call bench-rule,nessdb,$(NN)))
|
||||
$(eval $(call bench-rule,sqlite3,$(NN)))
|
||||
$(eval $(call bench-rule,ejdb,$(NN)))
|
||||
$(eval $(call bench-rule,vedisdb,$(NN)))
|
||||
$(eval $(call bench-rule,dummy,$(NN)))
|
||||
|
||||
$(eval $(call bench-rule,debug,10))
|
||||
|
||||
bench: bench-mdbx_$(NN).txt
|
||||
|
||||
.PHONY: bench-debug
|
||||
|
||||
bench-debug: bench-debug_10.txt
|
||||
|
||||
bench-quartet: bench-mdbx_$(NN).txt bench-lmdb_$(NN).txt bench-rocksdb_$(NN).txt bench-wiredtiger_$(NN).txt
|
||||
|
||||
endif
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
The OpenLDAP Public License
|
||||
Version 2.8, 17 August 2003
|
||||
|
||||
Redistribution and use of this software and associated documentation
|
||||
("Software"), with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions in source form must retain copyright statements
|
||||
and notices,
|
||||
|
||||
2. Redistributions in binary form must reproduce applicable copyright
|
||||
statements and notices, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution, and
|
||||
|
||||
3. Redistributions must contain a verbatim copy of this document.
|
||||
|
||||
The OpenLDAP Foundation may revise this license from time to time.
|
||||
Each revision is distinguished by a version number. You may use
|
||||
this Software under terms of this license revision or under the
|
||||
terms of any subsequent revision of the license.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
|
||||
CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
|
||||
OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The names of the authors and copyright holders must not be used in
|
||||
advertising or otherwise to promote the sale, use or other dealing
|
||||
in this Software without specific, written prior permission. Title
|
||||
to copyright in this Software shall at all times remain with copyright
|
||||
holders.
|
||||
|
||||
OpenLDAP is a registered trademark of the OpenLDAP Foundation.
|
||||
|
||||
Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
|
||||
California, USA. All Rights Reserved. Permission to copy and
|
||||
distribute verbatim copies of this document is granted.
|
||||
|
|
@ -1,591 +0,0 @@
|
|||
### The [repository now only mirrored on the Github](https://abf.io/erthink/libmdbx) due to illegal discriminatory restrictions for Russian Crimea and for sovereign crimeans.
|
||||
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
||||
-----
|
||||
|
||||
libmdbx
|
||||
======================================
|
||||
|
||||
_libmdbx_ is an extremely fast, compact, powerful, embedded
|
||||
transactional [key-value
|
||||
store](https://en.wikipedia.org/wiki/Key-value_database)
|
||||
database, with permissive [OpenLDAP Public License](LICENSE).
|
||||
_libmdbx_ has a specific set of properties and capabilities,
|
||||
focused on creating unique lightweight solutions with
|
||||
extraordinary performance.
|
||||
|
||||
The next version is under active non-public development and will be
|
||||
released as **_MithrilDB_** and `libmithrildb` for libraries & packages.
|
||||
Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is
|
||||
resembling silver but being stronger and lighter than steel. Therefore
|
||||
_MithrilDB_ is rightly relevant name.
|
||||
> _MithrilDB_ will be radically different from _libmdbx_ by the new
|
||||
> database format and API based on C++17, as well as the [Apache 2.0
|
||||
> License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this
|
||||
> revolution is to provide a clearer and robust API, add more features and
|
||||
> new valuable properties of database.
|
||||
|
||||
*The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет хорошо.*
|
||||
|
||||
[](https://travis-ci.org/leo-yuriev/libmdbx)
|
||||
[](https://ci.appveyor.com/project/leo-yuriev/libmdbx/branch/master)
|
||||
[](https://scan.coverity.com/projects/reopen-libmdbx)
|
||||
|
||||
## Table of Contents
|
||||
- [Overview](#overview)
|
||||
- [Comparison with other databases](#comparison-with-other-databases)
|
||||
- [History & Acknowledgments](#history)
|
||||
- [Description](#description)
|
||||
- [Key features](#key-features)
|
||||
- [Improvements over LMDB](#improvements-over-lmdb)
|
||||
- [Gotchas](#gotchas)
|
||||
- [Usage](#usage)
|
||||
- [Building](#building)
|
||||
- [Bindings](#bindings)
|
||||
- [Performance comparison](#performance-comparison)
|
||||
- [Integral performance](#integral-performance)
|
||||
- [Read scalability](#read-scalability)
|
||||
- [Sync-write mode](#sync-write-mode)
|
||||
- [Lazy-write mode](#lazy-write-mode)
|
||||
- [Async-write mode](#async-write-mode)
|
||||
- [Cost comparison](#cost-comparison)
|
||||
|
||||
-----
|
||||
|
||||
## Overview
|
||||
|
||||
_libmdbx_ is revised and extended descendant of amazing [Lightning
|
||||
Memory-Mapped
|
||||
Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||
_libmdbx_ inherits all features and characteristics from
|
||||
[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database),
|
||||
but resolves some issues and adds several features.
|
||||
|
||||
- _libmdbx_ guarantee data integrity after crash unless this was explicitly
|
||||
neglected in favour of write performance.
|
||||
|
||||
- _libmdbx_ allows multiple processes to read and update several key-value
|
||||
tables concurrently, while being
|
||||
[ACID](https://en.wikipedia.org/wiki/ACID)-compliant, with minimal
|
||||
overhead and Olog(N) operation cost.
|
||||
|
||||
- _libmdbx_ enforce
|
||||
[serializability](https://en.wikipedia.org/wiki/Serializability) for
|
||||
writers by single
|
||||
[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
|
||||
[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)
|
||||
for parallel readers without atomic/interlocked operations, while
|
||||
writing and reading transactions do not block each other.
|
||||
|
||||
- _libmdbx_ uses [B+Trees](https://en.wikipedia.org/wiki/B%2B_tree) and
|
||||
[Memory-Mapping](https://en.wikipedia.org/wiki/Memory-mapped_file),
|
||||
doesn't use [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging)
|
||||
which might be a caveat for some workloads.
|
||||
|
||||
- _libmdbx_ implements a simplified variant of the [Berkeley
|
||||
DB](https://en.wikipedia.org/wiki/Berkeley_DB) and/or
|
||||
[dbm](https://en.wikipedia.org/wiki/DBM_(computing)) API.
|
||||
|
||||
- _libmdbx_ supports Linux, Windows, MacOS, FreeBSD and other systems
|
||||
compliant with POSIX.1-2008.
|
||||
|
||||
### Comparison with other databases
|
||||
For now please refer to [chapter of "BoltDB comparison with other
|
||||
databases"](https://github.com/coreos/bbolt#comparison-with-other-databases)
|
||||
which is also (mostly) applicable to _libmdbx_.
|
||||
|
||||
### History
|
||||
At first the development was carried out within the
|
||||
[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP) project. About a
|
||||
year later _libmdbx_ was separated into standalone project, which was
|
||||
[presented at Highload++ 2015
|
||||
conference](http://www.highload.ru/2015/abstracts/1831.html).
|
||||
|
||||
Since 2017 _libmdbx_ is used in [Fast Positive Tables](https://github.com/leo-yuriev/libfpta),
|
||||
and development is funded by [Positive Technologies](https://www.ptsecurity.com).
|
||||
|
||||
### Acknowledgments
|
||||
Howard Chu <hyc@openldap.org> is the author of LMDB, from which
|
||||
originated the MDBX in 2015.
|
||||
|
||||
Martin Hedenfalk <martin@bzero.se> is the author of `btree.c` code, which
|
||||
was used for begin development of LMDB.
|
||||
|
||||
-----
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
## Key features
|
||||
|
||||
1. Key-value pairs are stored in ordered map(s), keys are always sorted,
|
||||
range lookups are supported.
|
||||
|
||||
2. Data is [memory-mapped](https://en.wikipedia.org/wiki/Memory-mapped_file)
|
||||
into each worker DB process, and could be accessed zero-copy from transactions.
|
||||
|
||||
3. Transactions are
|
||||
[ACID](https://en.wikipedia.org/wiki/ACID)-compliant, through to
|
||||
[MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)
|
||||
and [CoW](https://en.wikipedia.org/wiki/Copy-on-write). Writes are
|
||||
strongly serialized and aren't blocked by reads, transactions can't
|
||||
conflict with each other. Reads are guaranteed to get only commited data
|
||||
([relaxing serializability](https://en.wikipedia.org/wiki/Serializability#Relaxing_serializability)).
|
||||
|
||||
4. Read transactions are
|
||||
[non-blocking](https://en.wikipedia.org/wiki/Non-blocking_algorithm),
|
||||
don't use [atomic operations](https://en.wikipedia.org/wiki/Linearizability#High-level_atomic_operations).
|
||||
Readers don't block each other and aren't blocked by writers. Read
|
||||
performance scales linearly with CPU core count.
|
||||
> Nonetheless, "connect to DB" (starting the first read transaction in a thread) and
|
||||
> "disconnect from DB" (closing DB or thread termination) requires a lock
|
||||
> acquisition to register/unregister at the "readers table".
|
||||
|
||||
5. Keys with multiple values are stored efficiently without key
|
||||
duplication, sorted by value, including integers (valuable for
|
||||
secondary indexes).
|
||||
|
||||
6. Efficient operation on short fixed length keys,
|
||||
including 32/64-bit integer types.
|
||||
|
||||
7. [WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write
|
||||
Amplification Factor) и RAF (Read Amplification Factor) are Olog(N).
|
||||
|
||||
8. No [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) and
|
||||
transaction journal. In case of a crash no recovery needed. No need for
|
||||
regular maintenance. Backups can be made on the fly on working DB
|
||||
without freezing writers.
|
||||
|
||||
9. No additional memory management, all done by basic OS services.
|
||||
|
||||
|
||||
## Improvements over LMDB
|
||||
|
||||
_libmdbx_ is superior to _legendary [LMDB](https://symas.com/lmdb/)_ in
|
||||
terms of features and reliability, not inferior in performance. In
|
||||
comparison to LMDB, _libmdbx_ make things "just work" perfectly and
|
||||
out-of-the-box, not silently and catastrophically break down. The list
|
||||
below is pruned down to the improvements most notable and obvious from
|
||||
the user's point of view.
|
||||
|
||||
1. Automatic on-the-fly database size control by preset parameters, both
|
||||
reduction and increment.
|
||||
> _libmdbx_ manage the database size according to parameters specified
|
||||
> by `mdbx_env_set_geometry()` function,
|
||||
> ones include the growth step and the truncation threshold.
|
||||
|
||||
2. Automatic continuous zero-overhead database compactification.
|
||||
> _libmdbx_ logically move as possible a freed pages
|
||||
> at end of allocation area into unallocated space,
|
||||
> and then release such space if a lot of.
|
||||
|
||||
3. LIFO policy for recycling a Garbage Collection items. On systems with a disk
|
||||
write-back cache, this can significantly increase write performance, up to
|
||||
several times in a best case scenario.
|
||||
> LIFO means that for reuse pages will be taken which became unused the lastest.
|
||||
> Therefore the loop of database pages circulation becomes as short as possible.
|
||||
> In other words, the number of pages, that are overwritten in memory
|
||||
> and on disk during a series of write transactions, will be as small as possible.
|
||||
> Thus creates ideal conditions for the efficient operation of the disk write-back cache.
|
||||
|
||||
4. Fast estimation of range query result volume, i.e. how many items can
|
||||
be found between a `KEY1` and a `KEY2`. This is prerequisite for build
|
||||
and/or optimize query execution plans.
|
||||
> _libmdbx_ performs a rough estimate based only on b-tree pages that
|
||||
> are common for the both stacks of cursors that were set to corresponing
|
||||
> keys.
|
||||
|
||||
5. `mdbx_chk` tool for database integrity check.
|
||||
|
||||
6. Guarantee of database integrity even in asynchronous unordered write-to-disk mode.
|
||||
> _libmdbx_ propose additional trade-off by implementing append-like manner for updates
|
||||
> in `NOSYNC` and `MAPASYNC` modes, that avoid database corruption after a system crash
|
||||
> contrary to LMDB. Nevertheless, the `MDBX_UTTERLY_NOSYNC` mode available to match LMDB behaviour,
|
||||
> and for a special use-cases.
|
||||
|
||||
7. Automated steady flush to disk upon volume of changes and/or by
|
||||
timeout via cheap polling.
|
||||
|
||||
8. Sequence generation and three cheap persistent 64-bit markers with ACID.
|
||||
|
||||
9. Support for keys and values of zero length, including multi-values
|
||||
(aka sorted duplicates).
|
||||
|
||||
10. The handler of lack-of-space condition with a callback,
|
||||
that allow you to control and resolve such situations.
|
||||
|
||||
11. Support for opening a database in the exclusive mode, including on a network share.
|
||||
|
||||
12. Extended transaction info, including dirty and leftover space info
|
||||
for a write transaction, reading lag and hold over space for read
|
||||
transactions.
|
||||
|
||||
13. Extended whole-database info (aka environment) and reader enumeration.
|
||||
|
||||
14. Extended update or delete, _at once_ with getting previous value
|
||||
and addressing the particular item from multi-value with the same key.
|
||||
|
||||
15. Support for explicitly updating the existing record, not insertion a new one.
|
||||
|
||||
16. All cursors are uniformly, can be reused and should be closed explicitly,
|
||||
regardless ones were opened within write or read transaction.
|
||||
|
||||
17. Correct update of current record with `MDBX_CURRENT` flag when size
|
||||
of key or data was changed, including sorted duplicated.
|
||||
|
||||
18. Opening database handles is spared from race conditions and
|
||||
pre-opening is not needed.
|
||||
|
||||
19. Ability to determine whether the particular data is on a dirty page
|
||||
or not, that allows to avoid copy-out before updates.
|
||||
|
||||
20. Ability to determine whether the cursor is pointed to a key-value
|
||||
pair, to the first, to the last, or not set to anything.
|
||||
|
||||
21. Returning `MDBX_EMULTIVAL` error in case of ambiguous update or delete.
|
||||
|
||||
22. On **MacOS** the `fcntl(F_FULLFSYNC)` syscall is used _by
|
||||
default_ to synchronize data with the disk, as this is [the only way to
|
||||
guarantee data
|
||||
durability](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html)
|
||||
in case of power failure. Unfortunately, in scenarios with high write
|
||||
intensity, the use of `F_FULLFSYNC` significant degrades performance
|
||||
compared to LMDB, where the `fsync()` syscall is used. Therefore,
|
||||
_libmdbx_ allows you to override this behavior by defining the
|
||||
`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` option while build the library.
|
||||
|
||||
23. On **Windows** the `LockFileEx()` syscall is used for locking, since
|
||||
it allows place the database on network drives, and provides protection
|
||||
against incompetent user actions (aka
|
||||
[poka-yoke](https://en.wikipedia.org/wiki/Poka-yoke)). Therefore
|
||||
_libmdbx_ may be a little lag in performance tests from LMDB where a
|
||||
named mutexes are used.
|
||||
|
||||
|
||||
## Gotchas
|
||||
|
||||
1. There cannot be more than one writer at a time.
|
||||
> On the other hand, this allows serialize an updates and eliminate any
|
||||
> possibility of conflicts, deadlocks or logical errors.
|
||||
|
||||
2. No [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) means
|
||||
relatively big [WAF](https://en.wikipedia.org/wiki/Write_amplification)
|
||||
(Write Amplification Factor). Because of this syncing data to disk might
|
||||
be quite resource intensive and be main performance bottleneck during
|
||||
intensive write workload.
|
||||
> As compromise _libmdbx_ allows several modes of lazy and/or periodic
|
||||
> syncing, including `MAPASYNC` mode, which modificate data in memory and
|
||||
> asynchronously syncs data to disk, moment to sync is picked by OS.
|
||||
>
|
||||
> Although this should be used with care, synchronous transactions in a DB
|
||||
> with transaction journal will require 2 IOPS minimum (probably 3-4 in
|
||||
> practice) because of filesystem overhead, overhead depends on
|
||||
> filesystem, not on record count or record size. In _libmdbx_ IOPS count
|
||||
> will grow logarithmically depending on record count in DB (height of B+
|
||||
> tree) and will require at least 2 IOPS per transaction too.
|
||||
|
||||
3. [CoW](https://en.wikipedia.org/wiki/Copy-on-write) for
|
||||
[MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control)
|
||||
is done on memory page level with
|
||||
[B+trees](https://ru.wikipedia.org/wiki/B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE).
|
||||
Therefore altering data requires to copy about Olog(N) memory pages,
|
||||
which uses [memory bandwidth](https://en.wikipedia.org/wiki/Memory_bandwidth) and is main
|
||||
performance bottleneck in `MDBX_MAPASYNC` mode.
|
||||
> This is unavoidable, but isn't that bad. Syncing data to disk requires
|
||||
> much more similar operations which will be done by OS, therefore this is
|
||||
> noticeable only if data sync to persistent storage is fully disabled.
|
||||
> _libmdbx_ allows to safely save data to persistent storage with minimal
|
||||
> performance overhead. If there is no need to save data to persistent
|
||||
> storage then it's much more preferable to use `std::map`.
|
||||
|
||||
4. Massive altering of data during a parallel long read operation will
|
||||
increase the process work set, may exhaust entire free database space and
|
||||
result in subsequent write performance degradation.
|
||||
> _libmdbx_ mostly solve this issue by lack-of-space callback and `MDBX_LIFORECLAIM` mode.
|
||||
> See [`mdbx.h`](mdbx.h) with API description for details.
|
||||
> The "next" version of libmdbx (MithrilDB) will completely solve this.
|
||||
|
||||
5. There are no built-in checksums or digests to verify database integrity.
|
||||
> The "next" version of _libmdbx_ (MithrilDB) will solve this issue employing [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
## Source code embedding
|
||||
|
||||
_libmdbx_ provides two official ways for integration in source code form:
|
||||
|
||||
1. Using the amalgamated source code.
|
||||
> The amalgamated source code includes all files requires to build and
|
||||
> use _libmdbx_, but not for testing _libmdbx_ itself.
|
||||
|
||||
2. Adding the complete original source code as a `git submodule`.
|
||||
> This allows you to build as _libmdbx_ and testing tool.
|
||||
> On the other hand, this way requires you to pull git tags, and use C++11 compiler for test tool.
|
||||
|
||||
**_Please, avoid using any other techniques._** Otherwise, at least
|
||||
don't ask for support and don't name such chimeras `libmdbx`.
|
||||
|
||||
The amalgamated source code could be created from original clone of git
|
||||
repository on Linux by executing `make dist`. As a result, the desired
|
||||
set of files will be formed in the `dist` subdirectory.
|
||||
|
||||
## Building
|
||||
|
||||
Both amalgamated and original source code provides build through the use
|
||||
[CMake](https://cmake.org/) or [GNU
|
||||
Make](https://www.gnu.org/software/make/) with
|
||||
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). All build ways
|
||||
are completely traditional and have minimal prerequirements like
|
||||
`build-essential`, i.e. the non-obsolete C/C++ compiler and a
|
||||
[SDK](https://en.wikipedia.org/wiki/Software_development_kit) for the
|
||||
target platform. Obviously you need building tools itself, i.e. `git`,
|
||||
`cmake` or GNU `make` with `bash`.
|
||||
|
||||
So just use CMake or GNU Make in your habitual manner and feel free to
|
||||
fill an issue or make pull request in the case something will be
|
||||
unexpected or broken down.
|
||||
|
||||
#### DSO/DLL unloading and destructors of Thread-Local-Storage objects
|
||||
When building _libmdbx_ as a shared library or use static _libmdbx_ as a
|
||||
part of another dynamic library, it is advisable to make sure that your
|
||||
system ensures the correctness of the call destructors of
|
||||
Thread-Local-Storage objects when unloading dynamic libraries.
|
||||
|
||||
If this is not the case, then unloading a dynamic-link library with
|
||||
_libmdbx_ code inside, can result in either a resource leak or a crash
|
||||
due to calling destructors from an already unloaded DSO/DLL object. The
|
||||
problem can only manifest in a multithreaded application, which makes
|
||||
the unloading of shared dynamic libraries with _libmdbx_ code inside,
|
||||
after using _libmdbx_. It is known that TLS-destructors are properly
|
||||
maintained in the following cases:
|
||||
|
||||
- On all modern versions of Windows (Windows 7 and later).
|
||||
|
||||
- On systems with the
|
||||
[`__cxa_thread_atexit_impl()`](https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables)
|
||||
function in the standard C library, including systems with GNU libc
|
||||
version 2.18 and later.
|
||||
|
||||
- On systems with libpthread/ntpl from GNU libc with bug fixes
|
||||
[#21031](https://sourceware.org/bugzilla/show_bug.cgi?id=21031) and
|
||||
[#21032](https://sourceware.org/bugzilla/show_bug.cgi?id=21032), or
|
||||
where there are no similar bugs in the pthreads implementation.
|
||||
|
||||
### Linux and other platforms with GNU Make
|
||||
To build the library it is enough to execute `make all` in the directory
|
||||
of source code, and `make check` for execute the basic tests.
|
||||
|
||||
If the `make` installed on the system is not GNU Make, there will be a
|
||||
lot of errors from make when trying to build. In this case, perhaps you
|
||||
should use `gmake` instead of `make`, or even `gnu-make`, etc.
|
||||
|
||||
### FreeBSD and related platforms
|
||||
As a rule, in such systems, the default is to use Berkeley Make. And GNU
|
||||
Make is called by the gmake command or may be missing. In addition,
|
||||
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) may be absent.
|
||||
|
||||
You need to install the required components: GNU Make, bash, C and C++
|
||||
compilers compatible with GCC or CLANG. After that, to build the
|
||||
library, it is enough execute `gmake all` (or `make all`) in the
|
||||
directory with source code, and `gmake check` (or `make check`) to run
|
||||
the basic tests.
|
||||
|
||||
### Windows
|
||||
For build _libmdbx_ on Windows the _original_ CMake and [Microsoft Visual
|
||||
Studio](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) are
|
||||
recommended.
|
||||
|
||||
Building by MinGW, MSYS or Cygwin is potentially possible. However,
|
||||
these scripts are not tested and will probably require you to modify the
|
||||
CMakeLists.txt or Makefile respectively.
|
||||
|
||||
It should be noted that in _libmdbx_ was efforts to resolve
|
||||
runtime dependencies from CRT and other libraries Visual Studio.
|
||||
For this is enough define the `MDBX_AVOID_CRT` during build.
|
||||
|
||||
An example of running a basic test script can be found in the
|
||||
[CI-script](appveyor.yml) for [AppVeyor](https://www.appveyor.com/). To
|
||||
run the [long stochastic test scenario](test/long_stochastic.sh),
|
||||
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) is required, and
|
||||
the such testing is recommended with place the test data on the
|
||||
[RAM-disk](https://en.wikipedia.org/wiki/RAM_drive).
|
||||
|
||||
### MacOS
|
||||
Current [native build tools](https://en.wikipedia.org/wiki/Xcode) for
|
||||
MacOS include GNU Make, CLANG and an outdated version of bash.
|
||||
Therefore, to build the library, it is enough to run `make all` in the
|
||||
directory with source code, and run `make check` to execute the base
|
||||
tests. If something goes wrong, it is recommended to install
|
||||
[Homebrew](https://brew.sh/) and try again.
|
||||
|
||||
To run the [long stochastic test scenario](test/long_stochastic.sh), you
|
||||
will need to install the current (not outdated) version of
|
||||
[bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)). To do this, we
|
||||
recommend that you install [Homebrew](https://brew.sh/) and then execute
|
||||
`brew install bash`.
|
||||
|
||||
## Bindings
|
||||
|
||||
| Runtime | GitHub | Author |
|
||||
| -------- | ------ | ------ |
|
||||
| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) |
|
||||
| .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Performance comparison
|
||||
======================
|
||||
|
||||
All benchmarks were done by [IOArena](https://github.com/pmwkaa/ioarena)
|
||||
and multiple [scripts](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015)
|
||||
runs on Lenovo Carbon-2 laptop, i7-4600U 2.1 GHz, 8 Gb RAM,
|
||||
SSD SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Gb.
|
||||
|
||||
## Integral performance
|
||||
|
||||
Here showed sum of performance metrics in 3 benchmarks:
|
||||
|
||||
- Read/Search on 4 CPU cores machine;
|
||||
|
||||
- Transactions with [CRUD](https://en.wikipedia.org/wiki/CRUD)
|
||||
operations in sync-write mode (fdatasync is called after each
|
||||
transaction);
|
||||
|
||||
- Transactions with [CRUD](https://en.wikipedia.org/wiki/CRUD)
|
||||
operations in lazy-write mode (moment to sync data to persistent storage
|
||||
is decided by OS).
|
||||
|
||||
*Reasons why asynchronous mode isn't benchmarked here:*
|
||||
|
||||
1. It doesn't make sense as it has to be done with DB engines, oriented
|
||||
for keeping data in memory e.g. [Tarantool](https://tarantool.io/),
|
||||
[Redis](https://redis.io/)), etc.
|
||||
|
||||
2. Performance gap is too high to compare in any meaningful way.
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## Read Scalability
|
||||
|
||||
Summary performance with concurrent read/search queries in 1-2-4-8
|
||||
threads on 4 CPU cores machine.
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## Sync-write mode
|
||||
|
||||
- Linear scale on left and dark rectangles mean arithmetic mean
|
||||
transactions per second;
|
||||
|
||||
- Logarithmic scale on right is in seconds and yellow intervals mean
|
||||
execution time of transactions. Each interval shows minimal and maximum
|
||||
execution time, cross marks standard deviation.
|
||||
|
||||
**10,000 transactions in sync-write mode**. In case of a crash all data
|
||||
is consistent and state is right after last successful transaction.
|
||||
[fdatasync](https://linux.die.net/man/2/fdatasync) syscall is used after
|
||||
each write transaction in this mode.
|
||||
|
||||
In the benchmark each transaction contains combined CRUD operations (2
|
||||
inserts, 1 read, 1 update, 1 delete). Benchmark starts on empty database
|
||||
and after full run the database contains 10,000 small key-value records.
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## Lazy-write mode
|
||||
|
||||
- Linear scale on left and dark rectangles mean arithmetic mean of
|
||||
thousands transactions per second;
|
||||
|
||||
- Logarithmic scale on right in seconds and yellow intervals mean
|
||||
execution time of transactions. Each interval shows minimal and maximum
|
||||
execution time, cross marks standard deviation.
|
||||
|
||||
**100,000 transactions in lazy-write mode**. In case of a crash all data
|
||||
is consistent and state is right after one of last transactions, but
|
||||
transactions after it will be lost. Other DB engines use
|
||||
[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) or transaction
|
||||
journal for that, which in turn depends on order of operations in
|
||||
journaled filesystem. _libmdbx_ doesn't use WAL and hands I/O operations
|
||||
to filesystem and OS kernel (mmap).
|
||||
|
||||
In the benchmark each transaction contains combined CRUD operations (2
|
||||
inserts, 1 read, 1 update, 1 delete). Benchmark starts on empty database
|
||||
and after full run the database contains 100,000 small key-value
|
||||
records.
|
||||
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## Async-write mode
|
||||
|
||||
- Linear scale on left and dark rectangles mean arithmetic mean of
|
||||
thousands transactions per second;
|
||||
|
||||
- Logarithmic scale on right in seconds and yellow intervals mean
|
||||
execution time of transactions. Each interval shows minimal and maximum
|
||||
execution time, cross marks standard deviation.
|
||||
|
||||
**1,000,000 transactions in async-write mode**. In case of a crash all
|
||||
data will be consistent and state will be right after one of last
|
||||
transactions, but lost transaction count is much higher than in
|
||||
lazy-write mode. All DB engines in this mode do as little writes as
|
||||
possible on persistent storage. _libmdbx_ uses
|
||||
[msync(MS_ASYNC)](https://linux.die.net/man/2/msync) in this mode.
|
||||
|
||||
In the benchmark each transaction contains combined CRUD operations (2
|
||||
inserts, 1 read, 1 update, 1 delete). Benchmark starts on empty database
|
||||
and after full run the database contains 10,000 small key-value records.
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## Cost comparison
|
||||
|
||||
Summary of used resources during lazy-write mode benchmarks:
|
||||
|
||||
- Read and write IOPS;
|
||||
|
||||
- Sum of user CPU time and sys CPU time;
|
||||
|
||||
- Used space on persistent storage after the test and closed DB, but not
|
||||
waiting for the end of all internal housekeeping operations (LSM
|
||||
compactification, etc).
|
||||
|
||||
_ForestDB_ is excluded because benchmark showed it's resource
|
||||
consumption for each resource (CPU, IOPS) much higher than other engines
|
||||
which prevents to meaningfully compare it with them.
|
||||
|
||||
All benchmark data is gathered by
|
||||
[getrusage()](http://man7.org/linux/man-pages/man2/getrusage.2.html)
|
||||
syscall and by scanning data directory.
|
||||
|
||||

|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
$ objdump -f -h -j .text libmdbx.so
|
||||
|
||||
libmdbx.so: file format elf64-x86-64
|
||||
architecture: i386:x86-64, flags 0x00000150:
|
||||
HAS_SYMS, DYNAMIC, D_PAGED
|
||||
start address 0x0000000000003710
|
||||
|
||||
Sections:
|
||||
Idx Name Size VMA LMA File off Algn
|
||||
11 .text 00015eff 0000000000003710 0000000000003710 00003710 2**4
|
||||
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
||||
```
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
version: 0.3.2.{build}
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
TOOLSET: 142
|
||||
MDBX_BUILD_SHARED_LIBRARY: OFF
|
||||
MDBX_AVOID_CRT: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
TOOLSET: 142
|
||||
MDBX_BUILD_SHARED_LIBRARY: ON
|
||||
MDBX_AVOID_CRT: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
TOOLSET: 142
|
||||
MDBX_BUILD_SHARED_LIBRARY: OFF
|
||||
MDBX_AVOID_CRT: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
TOOLSET: 142
|
||||
MDBX_BUILD_SHARED_LIBRARY: ON
|
||||
MDBX_AVOID_CRT: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
CMAKE_GENERATOR: Visual Studio 15 2017
|
||||
TOOLSET: 141
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
TOOLSET: 140
|
||||
|
||||
branches:
|
||||
except:
|
||||
- coverity_scan
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
|
||||
before_build:
|
||||
- git clean -x -f -d
|
||||
- git submodule sync
|
||||
- git fetch --tags --prune
|
||||
- git submodule update --init --recursive
|
||||
- git submodule foreach --recursive git fetch --tags --prune
|
||||
- cmake --version
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
Write-Output "*******************************************************************************"
|
||||
Write-Output "Configuration: $env:CONFIGURATION"
|
||||
Write-Output "Platform: $env:PLATFORM"
|
||||
Write-Output "Toolchain: $env:CMAKE_GENERATOR v$env:TOOLSET"
|
||||
Write-Output "Options: MDBX_AVOID_CRT=$env:MDBX_AVOID_CRT MDBX_BUILD_SHARED_LIBRARY=$env:MDBX_BUILD_SHARED_LIBRARY"
|
||||
Write-Output "*******************************************************************************"
|
||||
|
||||
md _build -Force | Out-Null
|
||||
cd _build
|
||||
|
||||
$generator = $env:CMAKE_GENERATOR
|
||||
if ($env:TOOLSET -lt 142) {
|
||||
if ($env:PLATFORM -eq "x64") {
|
||||
$generator = "$generator Win64"
|
||||
}
|
||||
& cmake -G "$generator" -D CMAKE_CONFIGURATION_TYPES="Debug;Release" -D MDBX_AVOID_CRT:BOOL=$env:MDBX_AVOID_CRT -D MDBX_BUILD_SHARED_LIBRARY:BOOL=$env:MDBX_BUILD_SHARED_LIBRARY ..
|
||||
} else {
|
||||
& cmake -G "$generator" -A $env:PLATFORM -D CMAKE_CONFIGURATION_TYPES="Debug;Release" -DMDBX_AVOID_CRT:BOOL=$env:MDBX_AVOID_CRT -D MDBX_BUILD_SHARED_LIBRARY:BOOL=$env:MDBX_BUILD_SHARED_LIBRARY ..
|
||||
}
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Exec: $ErrorMessage"
|
||||
}
|
||||
Write-Output "*******************************************************************************"
|
||||
|
||||
& cmake --build . --config $env:CONFIGURATION
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Exec: $ErrorMessage"
|
||||
}
|
||||
Write-Output "*******************************************************************************"
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
if (($env:PLATFORM -ne "ARM") -and ($env:PLATFORM -ne "ARM64")) {
|
||||
& ./$env:CONFIGURATION/mdbx_test.exe --progress --console=no --pathname=test.db --dont-cleanup-after basic > test.log
|
||||
Get-Content test.log | Select-Object -last 42
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Exec: $ErrorMessage"
|
||||
} else {
|
||||
& ./$env:CONFIGURATION/mdbx_chk.exe -nvv test.db | Tee-Object -file chk.log | Select-Object -last 42
|
||||
}
|
||||
}
|
||||
|
||||
on_failure:
|
||||
- ps: Push-AppveyorArtifact \projects\libmdbx\_build\test.log
|
||||
- ps: Push-AppveyorArtifact \projects\libmdbx\_build\test.db
|
||||
- ps: Push-AppveyorArtifact \projects\libmdbx\_build\chk.log
|
||||
|
|
@ -1,666 +0,0 @@
|
|||
## Copyright (c) 2012-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.8.2)
|
||||
|
||||
if (CMAKE_VERSION MATCHES ".*MSVC.*")
|
||||
message(FATAL_ERROR "CMake from MSVC kit is unfit! "
|
||||
"Please use the original CMake from https://cmake.org/download/")
|
||||
endif()
|
||||
|
||||
if (NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED))
|
||||
message(FATAL_ERROR "This module required C or C++ to be enabled")
|
||||
endif()
|
||||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
include(CheckCXXSourceRuns)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CheckCXXCompilerFlag)
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_LOADED)
|
||||
include(CheckCSourceRuns)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckCCompilerFlag)
|
||||
endif()
|
||||
|
||||
# Check if the same compile family is used for both C and CXX
|
||||
if(CMAKE_C_COMPILER_LOADED AND CMAKE_CXX_COMPILER_LOADED AND
|
||||
NOT (CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID))
|
||||
message(WARNING "CMAKE_C_COMPILER_ID (${CMAKE_C_COMPILER_ID}) is different "
|
||||
"from CMAKE_CXX_COMPILER_ID (${CMAKE_CXX_COMPILER_ID}). "
|
||||
"The final binary may be unusable.")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
set(CMAKE_PRIMARY_LANG "CXX")
|
||||
else()
|
||||
set(CMAKE_PRIMARY_LANG "C")
|
||||
endif()
|
||||
|
||||
macro(check_compiler_flag flag variable)
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
check_cxx_compiler_flag(${flag} ${variable})
|
||||
else()
|
||||
check_c_compiler_flag(${flag} ${variable})
|
||||
endif()
|
||||
endmacro(check_compiler_flag)
|
||||
|
||||
# We support building with Clang and gcc. First check
|
||||
# what we're using for build.
|
||||
if(CMAKE_C_COMPILER_LOADED AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_COMPILER_IS_CLANG ON)
|
||||
set(CMAKE_COMPILER_IS_GNUCC OFF)
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXx_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_COMPILER_IS_CLANG ON)
|
||||
set(CMAKE_COMPILER_IS_GNUCXX OFF)
|
||||
endif()
|
||||
|
||||
# Hard coding the compiler version is ugly from cmake POV, but
|
||||
# at least gives user a friendly error message. The most critical
|
||||
# demand for C++ compiler is support of C++11 lambdas, added
|
||||
# only in version 4.5 https://gcc.gnu.org/projects/cxx0x.html
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
if(CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
|
||||
message(FATAL_ERROR "
|
||||
Your GCC version is ${CMAKE_C_COMPILER_VERSION}, please update")
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
|
||||
message(FATAL_ERROR "
|
||||
Your G++ version is ${CMAKE_CXX_COMPILER_VERSION}, please update")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_LOADED)
|
||||
# Check for Elbrus lcc
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} --version
|
||||
OUTPUT_VARIABLE tmp_lcc_probe_version
|
||||
RESULT_VARIABLE tmp_lcc_probe_result ERROR_QUIET)
|
||||
if(tmp_lcc_probe_result EQUAL 0)
|
||||
string(FIND "${tmp_lcc_probe_version}" "lcc:" tmp_lcc_marker)
|
||||
string(FIND "${tmp_lcc_probe_version}" ":e2k-" tmp_e2k_marker)
|
||||
if(tmp_lcc_marker GREATER -1 AND tmp_e2k_marker GREATER tmp_lcc_marker)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-version
|
||||
OUTPUT_VARIABLE CMAKE_C_COMPILER_VERSION
|
||||
RESULT_VARIABLE tmp_lcc_probe_result)
|
||||
set(CMAKE_COMPILER_IS_ELBRUSC ON)
|
||||
set(CMAKE_C_COMPILER_ID "Elbrus")
|
||||
else()
|
||||
set(CMAKE_COMPILER_IS_ELBRUSC OFF)
|
||||
endif()
|
||||
unset(tmp_lcc_marker)
|
||||
unset(tmp_e2k_marker)
|
||||
endif()
|
||||
unset(tmp_lcc_probe_version)
|
||||
unset(tmp_lcc_probe_result)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
# Check for Elbrus l++
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version
|
||||
OUTPUT_VARIABLE tmp_lxx_probe_version
|
||||
RESULT_VARIABLE tmp_lxx_probe_result ERROR_QUIET)
|
||||
if(tmp_lxx_probe_result EQUAL 0)
|
||||
string(FIND "${tmp_lxx_probe_version}" "lcc:" tmp_lcc_marker)
|
||||
string(FIND "${tmp_lxx_probe_version}" ":e2k-" tmp_e2k_marker)
|
||||
if(tmp_lcc_marker GREATER -1 AND tmp_e2k_marker GREATER tmp_lcc_marker)
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-version
|
||||
OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION
|
||||
RESULT_VARIABLE tmp_lxx_probe_result)
|
||||
set(CMAKE_COMPILER_IS_ELBRUSCXX ON)
|
||||
set(CMAKE_CXX_COMPILER_ID "Elbrus")
|
||||
else()
|
||||
set(CMAKE_COMPILER_IS_ELBRUSCXX OFF)
|
||||
endif()
|
||||
unset(tmp_lcc_marker)
|
||||
unset(tmp_e2k_marker)
|
||||
endif()
|
||||
unset(tmp_lxx_probe_version)
|
||||
unset(tmp_lxx_probe_result)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
set(MSVC64 1)
|
||||
endif()
|
||||
if(WIN32 AND CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
|
||||
execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -dumpmachine
|
||||
OUTPUT_VARIABLE __GCC_TARGET_MACHINE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(__GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
|
||||
set(MINGW64 1)
|
||||
endif()
|
||||
unset(__GCC_TARGET_MACHINE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_ELBRUSC OR CMAKE_SYSTEM_PROCESSOR MATCHES "e2k.*|E2K.*|elbrus.*|ELBRUS.*")
|
||||
set(E2K TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "Elbrus")
|
||||
elseif((MSVC64 OR MINGW64) AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(X86_64 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "x86_64")
|
||||
elseif(MINGW OR (MSVC AND NOT CMAKE_CROSSCOMPILING))
|
||||
set(X86_32 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "x86")
|
||||
elseif(CMAKE_COMPILER_IS_ELBRUSC OR CMAKE_SYSTEM_PROCESSOR MATCHES "e2k.*|E2K.*|elbrus.*|ELBRUS.*")
|
||||
set(E2K TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "Elbrus")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(X86_64 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "x86_64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*")
|
||||
set(X86_32 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "x86")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|ARM64.*)" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(AARCH64 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "ARM64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
|
||||
set(ARM32 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "ARM")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le.*" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(PPC64LE TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "PPC64LE")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64.*" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(PPC64 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "PPC64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc).*")
|
||||
set(PPC32 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "PPC")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips|MIPS)64.*" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(MIPS64 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "MIPS64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips|MIPS).*")
|
||||
set(MIPS32 TRUE)
|
||||
set(CMAKE_SYSTEM_ARCH "MIPS")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
check_compiler_flag("/WX" CC_HAS_WERROR)
|
||||
else()
|
||||
#
|
||||
# GCC started to warn for unused result starting from 4.2, and
|
||||
# this is when it introduced -Wno-unused-result
|
||||
# GCC can also be built on top of llvm runtime (on mac).
|
||||
check_compiler_flag("-Wno-unknown-pragmas" CC_HAS_WNO_UNKNOWN_PRAGMAS)
|
||||
check_compiler_flag("-Wextra" CC_HAS_WEXTRA)
|
||||
check_compiler_flag("-Werror" CC_HAS_WERROR)
|
||||
check_compiler_flag("-fexceptions" CC_HAS_FEXCEPTIONS)
|
||||
check_cxx_compiler_flag("-fcxx-exceptions" CC_HAS_FCXX_EXCEPTIONS)
|
||||
check_compiler_flag("-funwind-tables" CC_HAS_FUNWIND_TABLES)
|
||||
check_compiler_flag("-fno-omit-frame-pointer" CC_HAS_FNO_OMIT_FRAME_POINTER)
|
||||
check_compiler_flag("-fno-common" CC_HAS_FNO_COMMON)
|
||||
check_compiler_flag("-ggdb" CC_HAS_GGDB)
|
||||
check_compiler_flag("-fvisibility=hidden" CC_HAS_VISIBILITY)
|
||||
check_compiler_flag("-march=native" CC_HAS_ARCH_NATIVE)
|
||||
check_compiler_flag("-Og" CC_HAS_DEBUG_FRENDLY_OPTIMIZATION)
|
||||
check_compiler_flag("-Wall" CC_HAS_WALL)
|
||||
check_compiler_flag("-Ominimal" CC_HAS_OMINIMAL)
|
||||
check_compiler_flag("-ffunction-sections -fdata-sections" CC_HAS_SECTIONS)
|
||||
check_compiler_flag("-ffast-math" CC_HAS_FASTMATH)
|
||||
|
||||
# Check for an omp support
|
||||
set(CMAKE_REQUIRED_FLAGS "-fopenmp -Werror")
|
||||
check_cxx_source_compiles("int main(void) {
|
||||
#pragma omp parallel
|
||||
return 0;
|
||||
}" HAVE_OPENMP)
|
||||
set(CMAKE_REQUIRED_FLAGS "")
|
||||
endif()
|
||||
|
||||
# Check for LTO support by GCC
|
||||
if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
|
||||
unset(gcc_collect)
|
||||
unset(gcc_lto_wrapper)
|
||||
|
||||
if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 4.7)
|
||||
execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -v
|
||||
OUTPUT_VARIABLE gcc_info_v ERROR_VARIABLE gcc_info_v)
|
||||
|
||||
string(REGEX MATCH "^(.+\nCOLLECT_GCC=)([^ \n]+)(\n.+)$" gcc_collect_valid ${gcc_info_v})
|
||||
if(gcc_collect_valid)
|
||||
string(REGEX REPLACE "^(.+\nCOLLECT_GCC=)([^ \n]+)(\n.+)$" "\\2" gcc_collect ${gcc_info_v})
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "^(.+\nCOLLECT_LTO_WRAPPER=)([^ \n]+/lto-wrapper)(\n.+)$" gcc_lto_wrapper_valid ${gcc_info_v})
|
||||
if(gcc_lto_wrapper_valid)
|
||||
string(REGEX REPLACE "^(.+\nCOLLECT_LTO_WRAPPER=)([^ \n]+/lto-wrapper)(\n.+)$" "\\2" gcc_lto_wrapper ${gcc_info_v})
|
||||
endif()
|
||||
|
||||
set(gcc_suffix "")
|
||||
if(gcc_collect_valid AND gcc_collect)
|
||||
string(REGEX MATCH "^(.*cc)(-.+)$" gcc_suffix_valid ${gcc_collect})
|
||||
if(gcc_suffix_valid)
|
||||
string(REGEX MATCH "^(.*cc)(-.+)$" "\\2" gcc_suffix ${gcc_collect})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_filename_component(gcc_dir ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} DIRECTORY)
|
||||
if(NOT CMAKE_GCC_AR)
|
||||
find_program(CMAKE_GCC_AR NAMES gcc${gcc_suffix}-ar gcc-ar${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(NOT CMAKE_GCC_NM)
|
||||
find_program(CMAKE_GCC_NM NAMES gcc${gcc_suffix}-nm gcc-nm${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(NOT CMAKE_GCC_RANLIB)
|
||||
find_program(CMAKE_GCC_RANLIB NAMES gcc${gcc_suffix}-ranlib gcc-ranlib${gcc_suffix} PATHS ${gcc_dir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
unset(gcc_dir)
|
||||
unset(gcc_suffix_valid)
|
||||
unset(gcc_suffix)
|
||||
unset(gcc_lto_wrapper_valid)
|
||||
unset(gcc_collect_valid)
|
||||
unset(gcc_collect)
|
||||
unset(gcc_info_v)
|
||||
endif()
|
||||
|
||||
if(CMAKE_GCC_AR AND CMAKE_GCC_NM AND CMAKE_GCC_RANLIB AND gcc_lto_wrapper)
|
||||
message(STATUS "Found GCC's LTO toolset: ${gcc_lto_wrapper}, ${CMAKE_GCC_AR}, ${CMAKE_GCC_RANLIB}")
|
||||
set(GCC_LTO_CFLAGS "-flto -fno-fat-lto-objects -fuse-linker-plugin")
|
||||
set(GCC_LTO_AVAILABLE TRUE)
|
||||
message(STATUS "Link-Time Optimization by GCC is available")
|
||||
else()
|
||||
set(GCC_LTO_AVAILABLE FALSE)
|
||||
message(STATUS "Link-Time Optimization by GCC is NOT available")
|
||||
endif()
|
||||
unset(gcc_lto_wrapper)
|
||||
endif()
|
||||
|
||||
# check for LTO by MSVC
|
||||
if(MSVC)
|
||||
if(NOT MSVC_VERSION LESS 1600)
|
||||
set(MSVC_LTO_AVAILABLE TRUE)
|
||||
message(STATUS "Link-Time Optimization by MSVC is available")
|
||||
else()
|
||||
set(MSVC_LTO_AVAILABLE FALSE)
|
||||
message(STATUS "Link-Time Optimization by MSVC is NOT available")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check for LTO support by CLANG
|
||||
if(CMAKE_COMPILER_IS_CLANG)
|
||||
if(NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 3.5)
|
||||
execute_process(COMMAND ${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER} -print-search-dirs
|
||||
OUTPUT_VARIABLE clang_search_dirs)
|
||||
|
||||
unset(clang_bindir)
|
||||
unset(clang_libdir)
|
||||
string(REGEX MATCH "^(.*programs: =)([^:]*:)*([^:]+/llvm[-.0-9]+/bin[^:]*)(:[^:]*)*(\n.+)$" clang_bindir_valid ${clang_search_dirs})
|
||||
if(clang_bindir_valid)
|
||||
string(REGEX REPLACE "^(.*programs: =)([^:]*:)*([^:]+/llvm[-.0-9]+/bin[^:]*)(:[^:]*)*(\n.+)$" "\\3" clang_bindir ${clang_search_dirs})
|
||||
get_filename_component(clang_libdir "${clang_bindir}/../lib" REALPATH)
|
||||
if(clang_libdir)
|
||||
message(STATUS "Found CLANG/LLVM directories: ${clang_bindir}, ${clang_libdir}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT (clang_bindir AND clang_libdir))
|
||||
message(STATUS "Could NOT find CLANG/LLVM directories (bin and/or lib).")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CLANG_LD AND clang_bindir)
|
||||
find_program(CMAKE_CLANG_LD NAMES llvm-link link llvm-ld ld PATHS ${clang_bindir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(NOT CMAKE_CLANG_AR AND clang_bindir)
|
||||
find_program(CMAKE_CLANG_AR NAMES llvm-ar ar PATHS ${clang_bindir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(NOT CMAKE_CLANG_NM AND clang_bindir)
|
||||
find_program(CMAKE_CLANG_NM NAMES llvm-nm nm PATHS ${clang_bindir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(NOT CMAKE_CLANG_RANLIB AND clang_bindir)
|
||||
find_program(CMAKE_CLANG_RANLIB NAMES llvm-ranlib ranlib PATHS ${clang_bindir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
set(clang_lto_plugin_name "LLVMgold${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
if(NOT CMAKE_LD_GOLD AND clang_bindir)
|
||||
find_program(CMAKE_LD_GOLD NAMES ld.gold PATHS)
|
||||
endif()
|
||||
if(NOT CLANG_LTO_PLUGIN AND clang_libdir)
|
||||
find_file(CLANG_LTO_PLUGIN ${clang_lto_plugin_name} PATH ${clang_libdir} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
if(CLANG_LTO_PLUGIN)
|
||||
message(STATUS "Found CLANG/LLVM's plugin for LTO: ${CLANG_LTO_PLUGIN}")
|
||||
else()
|
||||
message(STATUS "Could NOT find CLANG/LLVM's plugin (${clang_lto_plugin_name}) for LTO.")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CLANG_LD AND CMAKE_CLANG_AR AND CMAKE_CLANG_NM AND CMAKE_CLANG_RANLIB)
|
||||
message(STATUS "Found CLANG/LLVM's binutils for LTO: ${CMAKE_CLANG_AR}, ${CMAKE_CLANG_RANLIB}")
|
||||
else()
|
||||
message(STATUS "Could NOT find CLANG/LLVM's binutils (ar, ranlib, nm) for LTO.")
|
||||
endif()
|
||||
|
||||
unset(clang_lto_plugin_name)
|
||||
unset(clang_libdir)
|
||||
unset(clang_bindir_valid)
|
||||
unset(clang_bindir)
|
||||
unset(clang_search_dirs)
|
||||
endif()
|
||||
|
||||
if((CLANG_LTO_PLUGIN AND CMAKE_LD_GOLD) AND
|
||||
(CMAKE_CLANG_LD AND CMAKE_CLANG_AR AND CMAKE_CLANG_NM AND CMAKE_CLANG_RANLIB))
|
||||
set(CLANG_LTO_AVAILABLE TRUE)
|
||||
message(STATUS "Link-Time Optimization by CLANG/LLVM is available")
|
||||
elseif(CMAKE_TOOLCHAIN_FILE AND NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 7.0)
|
||||
set(CLANG_LTO_AVAILABLE TRUE)
|
||||
if (NOT CMAKE_CLANG_AR)
|
||||
set(CMAKE_CLANG_AR ${CMAKE_AR})
|
||||
endif()
|
||||
if (NOT CMAKE_CLANG_NM)
|
||||
set(CMAKE_CLANG_NM ${CMAKE_NM})
|
||||
endif()
|
||||
if (NOT CMAKE_CLANG_RANLIB)
|
||||
set(CMAKE_CLANG_RANLIB ${CMAKE_RANLIB })
|
||||
endif()
|
||||
message(STATUS "Assume Link-Time Optimization by CLANG/LLVM is available via ${CMAKE_TOOLCHAIN_FILE}")
|
||||
else()
|
||||
set(CLANG_LTO_AVAILABLE FALSE)
|
||||
message(STATUS "Link-Time Optimization by CLANG/LLVM is NOT available")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Perform build type specific configuration.
|
||||
option(ENABLE_BACKTRACE "Enable output of fiber backtrace information in 'show
|
||||
fiber' administrative command. Only works on x86 architectures, if compiled
|
||||
with gcc. If GNU binutils and binutils-dev libraries are installed, backtrace
|
||||
is output with resolved function (symbol) names. Otherwise only frame
|
||||
addresses are printed." OFF)
|
||||
|
||||
set(HAVE_BFD False)
|
||||
if(ENABLE_BACKTRACE)
|
||||
if(NOT (X86_32 OR X86_64) OR NOT CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG})
|
||||
# We only know this option to work with gcc
|
||||
message(FATAL_ERROR "ENABLE_BACKTRACE option is set but the system
|
||||
is not x86 based (${CMAKE_SYSTEM_PROCESSOR}) or the compiler
|
||||
is not GNU GCC (${CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER}).")
|
||||
endif()
|
||||
# Use GNU bfd if present.
|
||||
find_library(BFD_LIBRARY NAMES libbfd.a)
|
||||
if(BFD_LIBRARY)
|
||||
check_library_exists(${BFD_LIBRARY} bfd_init "" HAVE_BFD_LIB)
|
||||
endif()
|
||||
find_library(IBERTY_LIBRARY NAMES libiberty.a)
|
||||
if(IBERTY_LIBRARY)
|
||||
check_library_exists(${IBERTY_LIBRARY} cplus_demangle "" HAVE_IBERTY_LIB)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_DEFINITIONS -DPACKAGE=${PACKAGE} -DPACKAGE_VERSION=${PACKAGE_VERSION})
|
||||
check_include_files(bfd.h HAVE_BFD_H)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS)
|
||||
find_package(ZLIB)
|
||||
if(HAVE_BFD_LIB AND HAVE_BFD_H AND HAVE_IBERTY_LIB AND ZLIB_FOUND)
|
||||
set(HAVE_BFD ON)
|
||||
set(BFD_LIBRARIES ${BFD_LIBRARY} ${IBERTY_LIBRARY} ${ZLIB_LIBRARIES})
|
||||
find_package_message(BFD_LIBRARIES "Found libbfd and dependencies"
|
||||
${BFD_LIBRARIES})
|
||||
if(TARGET_OS_FREEBSD AND NOT TARGET_OS_DEBIAN_FREEBSD)
|
||||
set(BFD_LIBRARIES ${BFD_LIBRARIES} iconv)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
macro(setup_compile_flags)
|
||||
# LY: save initial C/CXX flags
|
||||
if(NOT INITIAL_CMAKE_FLAGS_SAVED)
|
||||
if(MSVC)
|
||||
string(REGEX REPLACE "^(.*)(/EHsc)( *)(.*)$" "\\1/EHs\\3\\4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
set(INITIAL_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_STATIC_LINKER_FLAGS ${CMAKE_STATIC_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_MODULE_LINKER_FLAGS ${CMAKE_MODULE_LINKER_FLAGS} CACHE STRING "Initial CMake's flags" FORCE)
|
||||
set(INITIAL_CMAKE_FLAGS_SAVED TRUE CACHE INTERNAL "State of initial CMake's flags" FORCE)
|
||||
endif()
|
||||
|
||||
# LY: reset C/CXX flags
|
||||
set(CXX_FLAGS ${INITIAL_CMAKE_CXX_FLAGS})
|
||||
set(C_FLAGS ${INITIAL_CMAKE_C_FLAGS})
|
||||
set(EXE_LINKER_FLAGS ${INITIAL_CMAKE_EXE_LINKER_FLAGS})
|
||||
set(SHARED_LINKER_FLAGS ${INITIAL_CMAKE_SHARED_LINKER_FLAGS})
|
||||
set(STATIC_LINKER_FLAGS ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
|
||||
set(MODULE_LINKER_FLAGS ${INITIAL_CMAKE_MODULE_LINKER_FLAGS})
|
||||
|
||||
if(CC_HAS_FEXCEPTIONS)
|
||||
add_compile_flags("C;CXX" "-fexceptions")
|
||||
endif()
|
||||
if(CC_HAS_FCXX_EXCEPTIONS)
|
||||
add_compile_flags("CXX" "-fcxx-exceptions -frtti")
|
||||
endif()
|
||||
|
||||
# In C a global variable without a storage specifier (static/extern) and
|
||||
# without an initialiser is called a ’tentative definition’. The
|
||||
# language permits multiple tentative definitions in the single
|
||||
# translation unit; i.e. int foo; int foo; is perfectly ok. GNU
|
||||
# toolchain goes even further, allowing multiple tentative definitions
|
||||
# in *different* translation units. Internally, variables introduced via
|
||||
# tentative definitions are implemented as ‘common’ symbols. Linker
|
||||
# permits multiple definitions if they are common symbols, and it picks
|
||||
# one arbitrarily for inclusion in the binary being linked.
|
||||
#
|
||||
# -fno-common forces GNU toolchain to behave in a more
|
||||
# standard-conformant way in respect to tentative definitions and it
|
||||
# prevents common symbols generation. Since we are a cross-platform
|
||||
# project it really makes sense. There are toolchains that don’t
|
||||
# implement GNU style handling of the tentative definitions and there
|
||||
# are platforms lacking proper support for common symbols (osx).
|
||||
if(CC_HAS_FNO_COMMON)
|
||||
add_compile_flags("C;CXX" "-fno-common")
|
||||
endif()
|
||||
|
||||
if(CC_HAS_GGDB)
|
||||
add_compile_flags("C;CXX" "-ggdb")
|
||||
endif()
|
||||
|
||||
if(CC_HAS_WNO_UNKNOWN_PRAGMAS AND NOT HAVE_OPENMP)
|
||||
add_compile_flags("C;CXX" -Wno-unknown-pragmas)
|
||||
endif()
|
||||
|
||||
if(CC_HAS_SECTIONS)
|
||||
add_compile_flags("C;CXX" -ffunction-sections -fdata-sections)
|
||||
elseif(MSVC)
|
||||
add_compile_flags("C;CXX" /Gy)
|
||||
endif()
|
||||
|
||||
# We must set -fno-omit-frame-pointer here, since we rely
|
||||
# on frame pointer when getting a backtrace, and it must
|
||||
# be used consistently across all object files.
|
||||
# The same reasoning applies to -fno-stack-protector switch.
|
||||
if(ENABLE_BACKTRACE)
|
||||
if(CC_HAS_FNO_OMIT_FRAME_POINTER)
|
||||
add_compile_flags("C;CXX" "-fno-omit-frame-pointer")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if (MSVC_VERSION LESS 1900)
|
||||
message(FATAL_ERROR "At least \"Microsoft C/C++ Compiler\" version 19.0.24234.1 (Visual Studio 2015 Update 3) is required.")
|
||||
endif()
|
||||
add_compile_flags("CXX" "/Zc:__cplusplus")
|
||||
add_compile_flags("C;CXX" "/W4")
|
||||
add_compile_flags("C;CXX" "/utf-8")
|
||||
else()
|
||||
if(CC_HAS_WALL)
|
||||
add_compile_flags("C;CXX" "-Wall")
|
||||
endif()
|
||||
if(CC_HAS_WEXTRA)
|
||||
add_compile_flags("C;CXX" "-Wextra")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNU${CMAKE_PRIMARY_LANG}
|
||||
AND CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 5)
|
||||
# G++ bug. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31488
|
||||
add_compile_flags("CXX" "-Wno-invalid-offsetof")
|
||||
endif()
|
||||
|
||||
add_definitions("-D__STDC_FORMAT_MACROS=1")
|
||||
add_definitions("-D__STDC_LIMIT_MACROS=1")
|
||||
add_definitions("-D__STDC_CONSTANT_MACROS=1")
|
||||
add_definitions("-D_HAS_EXCEPTIONS=1")
|
||||
|
||||
# Only add -Werror if it's a debug build, done by developers.
|
||||
# Release builds should not cause extra trouble.
|
||||
if(CC_HAS_WERROR AND (CI OR CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
if(MSVC)
|
||||
add_compile_flags("C;CXX" "/WX")
|
||||
elseif(CMAKE_COMPILER_IS_CLANG)
|
||||
if (NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 6)
|
||||
add_compile_flags("C;CXX" "-Werror")
|
||||
endif()
|
||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||
if (NOT CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 6)
|
||||
add_compile_flags("C;CXX" "-Werror")
|
||||
endif()
|
||||
else()
|
||||
add_compile_flags("C;CXX" "-Werror")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_OPENMP)
|
||||
add_compile_flags("C;CXX" "-fopenmp")
|
||||
endif()
|
||||
|
||||
if (ENABLE_ASAN)
|
||||
add_compile_flags("C;CXX" -fsanitize=address)
|
||||
endif()
|
||||
|
||||
if(ENABLE_GCOV)
|
||||
if(NOT HAVE_GCOV)
|
||||
message(FATAL_ERROR
|
||||
"ENABLE_GCOV option requested but gcov library is not found")
|
||||
endif()
|
||||
|
||||
add_compile_flags("C;CXX" "-fprofile-arcs" "-ftest-coverage")
|
||||
set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
# add_library(gcov SHARED IMPORTED)
|
||||
endif()
|
||||
|
||||
if(ENABLE_GPROF)
|
||||
add_compile_flags("C;CXX" "-pg")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND LTO_ENABLED)
|
||||
add_compile_flags("C;CXX" ${GCC_LTO_CFLAGS})
|
||||
set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm -fwhole-program")
|
||||
set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm")
|
||||
set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${GCC_LTO_CFLAGS} -fverbose-asm")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
|
||||
# Pass the same optimization flags to the linker
|
||||
set(compile_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
|
||||
set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${compile_flags}")
|
||||
set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${compile_flags}")
|
||||
set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${compile_flags}")
|
||||
unset(compile_flags)
|
||||
else()
|
||||
add_compile_flags("CXX" "-flto-odr-type-merging")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC AND LTO_ENABLED)
|
||||
add_compile_flags("C;CXX" "/GL")
|
||||
foreach(linkmode IN ITEMS EXE SHARED STATIC MODULE)
|
||||
set(${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS} /LTCG")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL:NO *)(.*)$" "\\1\\3" ${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS}")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL:YES *)(.*)$" "\\1\\3" ${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS}")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL *)(.*)$" "\\1\\3" ${linkmode}_LINKER_FLAGS "${${linkmode}_LINKER_FLAGS}")
|
||||
string(STRIP "${${linkmode}_LINKER_FLAGS}" ${linkmode}_LINKER_FLAGS)
|
||||
foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES ITEMS Release MinSizeRel RelWithDebInfo Debug)
|
||||
string(TOUPPER "${config}" config_uppercase)
|
||||
if(DEFINED "CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL:NO *)(.*)$" "\\1\\3" altered_flags "${CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}}")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL:YES *)(.*)$" "\\1\\3" altered_flags "${altered_flags}")
|
||||
string(REGEX REPLACE "^(.*)(/INCREMENTAL *)(.*)$" "\\1\\3" altered_flags "${altered_flags}")
|
||||
string(STRIP "${altered_flags}" altered_flags)
|
||||
if(NOT "${altered_flags}" STREQUAL "${CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase}}")
|
||||
set(CMAKE_${linkmode}_LINKER_FLAGS_${config_uppercase} "${altered_flags}" CACHE STRING "Altered: '/INCREMENTAL' removed for LTO" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach(config)
|
||||
endforeach(linkmode)
|
||||
unset(linkmode)
|
||||
|
||||
foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES ITEMS Release MinSizeRel RelWithDebInfo)
|
||||
foreach(lang IN ITEMS C CXX)
|
||||
string(TOUPPER "${config}" config_uppercase)
|
||||
if(DEFINED "CMAKE_${lang}_FLAGS_${config_uppercase}")
|
||||
string(REPLACE "/O2" "/Ox" altered_flags "${CMAKE_${lang}_FLAGS_${config_uppercase}}")
|
||||
if(NOT "${altered_flags}" STREQUAL "${CMAKE_${lang}_FLAGS_${config_uppercase}}")
|
||||
set(CMAKE_${lang}_FLAGS_${config_uppercase} "${altered_flags}" CACHE STRING "Altered: '/O2' replaced by '/Ox' for LTO" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
unset(config_uppercase)
|
||||
endforeach(lang)
|
||||
endforeach(config)
|
||||
unset(altered_flags)
|
||||
unset(lang)
|
||||
unset(config)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_CLANG AND OSX_ARCHITECTURES)
|
||||
set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
|
||||
set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
|
||||
set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} -Wl,-keep_dwarf_unwind")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_CLANG AND LTO_ENABLED)
|
||||
if(CMAKE_${CMAKE_PRIMARY_LANG}_COMPILER_VERSION VERSION_LESS 3.9)
|
||||
set(CLANG_LTO_FLAG "-flto")
|
||||
else()
|
||||
set(CLANG_LTO_FLAG "-flto=thin")
|
||||
endif()
|
||||
add_compile_flags("C;CXX" ${CLANG_LTO_FLAG})
|
||||
set(EXE_LINKER_FLAGS "${EXE_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm -fwhole-program")
|
||||
set(SHARED_LINKER_FLAGS "${SHARED_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm")
|
||||
set(MODULE_LINKER_FLAGS "${MODULE_LINKER_FLAGS} ${CLANG_LTO_FLAG} -fverbose-asm")
|
||||
endif()
|
||||
|
||||
# LY: push C/CXX flags into the cache
|
||||
set(CMAKE_CXX_FLAGS ${CXX_FLAGS} CACHE STRING "Flags used by the C++ compiler during all build types" FORCE)
|
||||
set(CMAKE_C_FLAGS ${C_FLAGS} CACHE STRING "Flags used by the C compiler during all build types" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${EXE_LINKER_FLAGS} CACHE STRING "Flags used by the linker" FORCE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS ${SHARED_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of dll's" FORCE)
|
||||
set(CMAKE_STATIC_LINKER_FLAGS ${STATIC_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of static libraries" FORCE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS ${MODULE_LINKER_FLAGS} CACHE STRING "Flags used by the linker during the creation of modules" FORCE)
|
||||
unset(CXX_FLAGS)
|
||||
unset(C_FLAGS)
|
||||
unset(EXE_LINKER_FLAGS)
|
||||
unset(SHARED_LINKER_FLAGS)
|
||||
unset(STATIC_LINKER_FLAGS)
|
||||
unset(MODULE_LINKER_FLAGS)
|
||||
endmacro(setup_compile_flags)
|
||||
|
||||
# determine library for for std::filesystem
|
||||
set(LIBCXX_FILESYSTEM "")
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
|
||||
set(LIBCXX_FILESYSTEM "stdc++fs")
|
||||
endif()
|
||||
elseif (CMAKE_COMPILER_IS_CLANG)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||
set(LIBCXX_FILESYSTEM "c++experimental")
|
||||
else()
|
||||
set(LIBCXX_FILESYSTEM "stdc++fs")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_policy(POP)
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
## Copyright (c) 2012-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.8.2)
|
||||
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(gcov __gcov_flush "" HAVE_GCOV)
|
||||
|
||||
option(ENABLE_GCOV
|
||||
"Enable integration with gcov, a code coverage program" OFF)
|
||||
|
||||
option(ENABLE_GPROF
|
||||
"Enable integration with gprof, a performance analyzing tool" OFF)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
include(CheckIncludeFileCXX)
|
||||
check_include_file_cxx(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
|
||||
else()
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
|
||||
endif()
|
||||
|
||||
option(MDBX_USE_VALGRIND "Enable integration with valgrind, a memory analyzing tool" OFF)
|
||||
if(MDBX_USE_VALGRIND AND NOT HAVE_VALGRIND_MEMCHECK_H)
|
||||
message(FATAL_ERROR "MDBX_USE_VALGRIND option is set but valgrind/memcheck.h is not found")
|
||||
endif()
|
||||
|
||||
option(ENABLE_ASAN
|
||||
"Enable AddressSanitizer, a fast memory error detector based on compiler instrumentation" OFF)
|
||||
|
||||
cmake_policy(POP)
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
## Copyright (c) 2012-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.8.2)
|
||||
|
||||
macro(add_compile_flags langs)
|
||||
foreach(_lang ${langs})
|
||||
string(REPLACE ";" " " _flags "${ARGN}")
|
||||
if(CMAKE_CXX_COMPILER_LOADED AND _lang STREQUAL "CXX")
|
||||
set("${_lang}_FLAGS" "${${_lang}_FLAGS} ${_flags}")
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_LOADED AND _lang STREQUAL "C")
|
||||
set("${_lang}_FLAGS" "${${_lang}_FLAGS} ${_flags}")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_lang)
|
||||
unset(_flags)
|
||||
endmacro(add_compile_flags)
|
||||
|
||||
macro(set_source_files_compile_flags)
|
||||
foreach(file ${ARGN})
|
||||
get_filename_component(_file_ext ${file} EXT)
|
||||
set(_lang "")
|
||||
if("${_file_ext}" STREQUAL ".m")
|
||||
set(_lang OBJC)
|
||||
# CMake believes that Objective C is a flavor of C++, not C,
|
||||
# and uses g++ compiler for .m files.
|
||||
# LANGUAGE property forces CMake to use CC for ${file}
|
||||
set_source_files_properties(${file} PROPERTIES LANGUAGE C)
|
||||
elseif("${_file_ext}" STREQUAL ".mm")
|
||||
set(_lang OBJCXX)
|
||||
endif()
|
||||
|
||||
if(_lang)
|
||||
get_source_file_property(_flags ${file} COMPILE_FLAGS)
|
||||
if("${_flags}" STREQUAL "NOTFOUND")
|
||||
set(_flags "${CMAKE_${_lang}_FLAGS}")
|
||||
else()
|
||||
set(_flags "${_flags} ${CMAKE_${_lang}_FLAGS}")
|
||||
endif()
|
||||
# message(STATUS "Set (${file} ${_flags}")
|
||||
set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS
|
||||
"${_flags}")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_file_ext)
|
||||
unset(_lang)
|
||||
endmacro(set_source_files_compile_flags)
|
||||
|
||||
macro(fetch_version name version_file)
|
||||
set(${name}_VERSION "")
|
||||
set(${name}_GIT_DESCRIBE "")
|
||||
set(${name}_GIT_TIMESTAMP "")
|
||||
set(${name}_GIT_TREE "")
|
||||
set(${name}_GIT_COMMIT "")
|
||||
set(${name}_GIT_REVISION 0)
|
||||
set(${name}_GIT_VERSION "")
|
||||
if(GIT)
|
||||
execute_process(COMMAND ${GIT} describe --tags --long --dirty=-dirty
|
||||
OUTPUT_VARIABLE ${name}_GIT_DESCRIBE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_DESCRIBE" STREQUAL "")
|
||||
message(FATAL_ERROR "Please fetch tags and/or install latest version of git ('describe --tags --long --dirty' failed)")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${GIT} show --no-patch --format=%cI HEAD
|
||||
OUTPUT_VARIABLE ${name}_GIT_TIMESTAMP
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_TIMESTAMP" STREQUAL "%cI")
|
||||
execute_process(COMMAND ${GIT} show --no-patch --format=%ci HEAD
|
||||
OUTPUT_VARIABLE ${name}_GIT_TIMESTAMP
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_TIMESTAMP" STREQUAL "%ci")
|
||||
message(FATAL_ERROR "Please install latest version of git ('show --no-patch --format=%cI HEAD' failed)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${GIT} show --no-patch --format=%T HEAD
|
||||
OUTPUT_VARIABLE ${name}_GIT_TREE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_TREE" STREQUAL "")
|
||||
message(FATAL_ERROR "Please install latest version of git ('show --no-patch --format=%T HEAD' failed)")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${GIT} show --no-patch --format=%H HEAD
|
||||
OUTPUT_VARIABLE ${name}_GIT_COMMIT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_COMMIT" STREQUAL "")
|
||||
message(FATAL_ERROR "Please install latest version of git ('show --no-patch --format=%H HEAD' failed)")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${GIT} rev-list --count --no-merges HEAD
|
||||
OUTPUT_VARIABLE ${name}_GIT_REVISION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR "${name}_GIT_REVISION" STREQUAL "")
|
||||
message(FATAL_ERROR "Please install latest version of git ('rev-list --count --no-merges HEAD' failed)")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "^(v)?([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" git_version_valid "${${name}_GIT_DESCRIBE}")
|
||||
if(git_version_valid)
|
||||
string(REGEX REPLACE "^(v)?([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)?" "\\2;\\3;\\4" ${name}_GIT_VERSION ${${name}_GIT_DESCRIBE})
|
||||
else()
|
||||
string(REGEX MATCH "^(v)?([0-9]+)\\.([0-9]+)(.*)?" git_version_valid "${${name}_GIT_DESCRIBE}")
|
||||
if(git_version_valid)
|
||||
string(REGEX REPLACE "^(v)?([0-9]+)\\.([0-9]+)(.*)?" "\\2;\\3;0" ${name}_GIT_VERSION ${${name}_GIT_DESCRIBE})
|
||||
else()
|
||||
message(AUTHOR_WARNING "Bad ${name} version \"${${name}_GIT_DESCRIBE}\"; falling back to 0.0.0 (have you made an initial release?)")
|
||||
set(${name}_GIT_VERSION "0;0;0")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ${name}_GIT_VERSION OR NOT ${name}_GIT_TIMESTAMP OR NOT ${name}_GIT_REVISION)
|
||||
message(WARNING "Unable to retrive ${name} version from git.")
|
||||
set(${name}_GIT_VERSION "0;0;0;0")
|
||||
set(${name}_GIT_TIMESTAMP "")
|
||||
set(${name}_GIT_REVISION 0)
|
||||
|
||||
# Try to get version from VERSION file
|
||||
if(EXISTS "${version_file}")
|
||||
file(STRINGS "${version_file}" ${name}_VERSION)
|
||||
endif()
|
||||
|
||||
if(NOT ${name}_VERSION)
|
||||
message(WARNING "Unable to retrive ${name} version from \"${version_file}\" file.")
|
||||
set(${name}_VERSION_LIST ${${name}_GIT_VERSION})
|
||||
string(REPLACE ";" "." ${name}_VERSION "${${name}_GIT_VERSION}")
|
||||
else()
|
||||
string(REPLACE "." ";" ${name}_VERSION_LIST ${${name}_VERSION})
|
||||
endif()
|
||||
|
||||
else()
|
||||
list(APPEND ${name}_GIT_VERSION ${${name}_GIT_REVISION})
|
||||
set(${name}_VERSION_LIST ${${name}_GIT_VERSION})
|
||||
string(REPLACE ";" "." ${name}_VERSION "${${name}_GIT_VERSION}")
|
||||
endif()
|
||||
|
||||
list(GET ${name}_VERSION_LIST 0 "${name}_VERSION_MAJOR")
|
||||
list(GET ${name}_VERSION_LIST 1 "${name}_VERSION_MINOR")
|
||||
list(GET ${name}_VERSION_LIST 2 "${name}_VERSION_RELEASE")
|
||||
list(GET ${name}_VERSION_LIST 3 "${name}_VERSION_REVISION")
|
||||
|
||||
set(${name}_VERSION_MAJOR ${${name}_VERSION_MAJOR} PARENT_SCOPE)
|
||||
set(${name}_VERSION_MINOR ${${name}_VERSION_MINOR} PARENT_SCOPE)
|
||||
set(${name}_VERSION_RELEASE ${${name}_VERSION_RELEASE} PARENT_SCOPE)
|
||||
set(${name}_VERSION_REVISION ${${name}_VERSION_REVISION} PARENT_SCOPE)
|
||||
set(${name}_VERSION ${${name}_VERSION} PARENT_SCOPE)
|
||||
|
||||
set(${name}_GIT_DESCRIBE ${${name}_GIT_DESCRIBE} PARENT_SCOPE)
|
||||
set(${name}_GIT_TIMESTAMP ${${name}_GIT_TIMESTAMP} PARENT_SCOPE)
|
||||
set(${name}_GIT_TREE ${${name}_GIT_TREE} PARENT_SCOPE)
|
||||
set(${name}_GIT_COMMIT ${${name}_GIT_COMMIT} PARENT_SCOPE)
|
||||
set(${name}_GIT_REVISION ${${name}_GIT_REVISION} PARENT_SCOPE)
|
||||
set(${name}_GIT_VERSION ${${name}_GIT_VERSION} PARENT_SCOPE)
|
||||
endmacro(fetch_version)
|
||||
|
||||
cmake_policy(POP)
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
set(TARGET mdbx_example)
|
||||
project(${TARGET})
|
||||
|
||||
add_executable(${TARGET} example-mdbx.c)
|
||||
|
||||
target_link_libraries(${TARGET} mdbx)
|
||||
|
|
@ -1 +0,0 @@
|
|||
See [example-mdbx.c](example-mdbx.c) as an example of using _libmdbx_, and do a line-by-line comparison of it with the [sample-bdb.txt](sample-bdb.txt) file.
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/* MDBX usage examle
|
||||
*
|
||||
* Do a line-by-line comparison of this and sample-bdb.txt
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2017 Ilya Shipitsin <chipitsine@gmail.com>.
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "mdbx.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
int rc;
|
||||
MDBX_env *env = NULL;
|
||||
MDBX_dbi dbi = 0;
|
||||
MDBX_val key, data;
|
||||
MDBX_txn *txn = NULL;
|
||||
MDBX_cursor *cursor = NULL;
|
||||
char sval[32];
|
||||
|
||||
rc = mdbx_env_create(&env);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_env_create: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
rc = mdbx_env_open(env, "./example-db",
|
||||
MDBX_NOSUBDIR | MDBX_COALESCE | MDBX_LIFORECLAIM, 0664);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_env_open: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
rc = mdbx_txn_begin(env, NULL, 0, &txn);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_txn_begin: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
rc = mdbx_dbi_open(txn, NULL, 0, &dbi);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_dbi_open: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
key.iov_len = sizeof(int);
|
||||
key.iov_base = sval;
|
||||
data.iov_len = sizeof(sval);
|
||||
data.iov_base = sval;
|
||||
|
||||
sprintf(sval, "%03x %d foo bar", 32, 3141592);
|
||||
rc = mdbx_put(txn, dbi, &key, &data, 0);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_put: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
rc = mdbx_txn_commit(txn);
|
||||
if (rc) {
|
||||
fprintf(stderr, "mdbx_txn_commit: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
txn = NULL;
|
||||
|
||||
rc = mdbx_txn_begin(env, NULL, MDBX_RDONLY, &txn);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_txn_begin: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
rc = mdbx_cursor_open(txn, dbi, &cursor);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
fprintf(stderr, "mdbx_cursor_open: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
while ((rc = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n", key.iov_base, (int)key.iov_len,
|
||||
(char *)key.iov_base, data.iov_base, (int)data.iov_len,
|
||||
(char *)data.iov_base);
|
||||
found += 1;
|
||||
}
|
||||
if (rc != MDBX_NOTFOUND || found == 0) {
|
||||
fprintf(stderr, "mdbx_cursor_get: (%d) %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
} else {
|
||||
rc = MDBX_SUCCESS;
|
||||
}
|
||||
bailout:
|
||||
if (cursor)
|
||||
mdbx_cursor_close(cursor);
|
||||
if (txn)
|
||||
mdbx_txn_abort(txn);
|
||||
if (dbi)
|
||||
mdbx_dbi_close(env, dbi);
|
||||
if (env)
|
||||
mdbx_env_close(env);
|
||||
return (rc != MDBX_SUCCESS) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/* BerkeleyDB toy/sample
|
||||
*
|
||||
* Do a line-by-line comparison of this and example-mdbx.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <db.h>
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
int rc;
|
||||
DB_ENV *env;
|
||||
DB *dbi;
|
||||
DBT key, data;
|
||||
DB_TXN *txn;
|
||||
DBC *cursor;
|
||||
char sval[32], kval[32];
|
||||
|
||||
/* Note: Most error checking omitted for simplicity */
|
||||
|
||||
#define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
|
||||
rc = db_env_create(&env, 0);
|
||||
rc = env->open(env, "./testdb", FLAGS, 0664);
|
||||
rc = db_create(&dbi, env, 0);
|
||||
rc = env->txn_begin(env, NULL, &txn, 0);
|
||||
rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
|
||||
|
||||
memset(&key, 0, sizeof(DBT));
|
||||
memset(&data, 0, sizeof(DBT));
|
||||
key.size = sizeof(int);
|
||||
key.data = sval;
|
||||
data.size = sizeof(sval);
|
||||
data.data = sval;
|
||||
|
||||
sprintf(sval, "%03x %d foo bar", 32, 3141592);
|
||||
rc = dbi->put(dbi, txn, &key, &data, 0);
|
||||
rc = txn->commit(txn, 0);
|
||||
if (rc) {
|
||||
fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = env->txn_begin(env, NULL, &txn, 0);
|
||||
rc = dbi->cursor(dbi, txn, &cursor, 0);
|
||||
key.flags = DB_DBT_USERMEM;
|
||||
key.data = kval;
|
||||
key.ulen = sizeof(kval);
|
||||
data.flags = DB_DBT_USERMEM;
|
||||
data.data = sval;
|
||||
data.ulen = sizeof(sval);
|
||||
while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
|
||||
printf("key: %p %.*s, data: %p %.*s\n",
|
||||
key.data, (int) key.size, (char *) key.data,
|
||||
data.data, (int) data.size, (char *) data.data);
|
||||
}
|
||||
rc = cursor->c_close(cursor);
|
||||
rc = txn->abort(txn);
|
||||
leave:
|
||||
rc = dbi->close(dbi, 0);
|
||||
rc = env->close(env, 0);
|
||||
return rc;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,184 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
set(TARGET mdbx)
|
||||
project(${TARGET})
|
||||
|
||||
set(MDBX_VERSION_MAJOR 0)
|
||||
set(MDBX_VERSION_MINOR 3)
|
||||
set(MDBX_VERSION_RELEASE 1)
|
||||
set(MDBX_VERSION_REVISION 0)
|
||||
|
||||
set(MDBX_VERSION_STRING ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_RELEASE})
|
||||
|
||||
enable_language(C)
|
||||
enable_language(CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED on)
|
||||
|
||||
add_definitions(-DNDEBUG=1 -DMDBX_DEBUG=0 -DLIBMDBX_EXPORTS=1 -D_GNU_SOURCE=1)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
get_directory_property(hasParent PARENT_DIRECTORY)
|
||||
if(hasParent)
|
||||
set(STANDALONE_BUILD 0)
|
||||
else()
|
||||
set(STANDALONE_BUILD 1)
|
||||
enable_testing()
|
||||
|
||||
if (CMAKE_C_COMPILER_ID MATCHES GNU)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat-security")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wwrite-strings")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmax-errors=20")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wunused-function -Wunused-variable -Wunused-value -Wmissing-declarations")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finline-functions-called-once")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-packed-bitfield-compat")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g3")
|
||||
endif()
|
||||
|
||||
if (COVERAGE)
|
||||
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
message(FATAL_ERROR "Coverage requires -DCMAKE_BUILD_TYPE=Debug Current value=${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
message(STATUS "Setting coverage compiler flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb3 -O0 --coverage -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -ggdb3 -O0 --coverage -fprofile-arcs -ftest-coverage")
|
||||
add_definitions(-DCOVERAGE_TEST)
|
||||
endif()
|
||||
|
||||
if (NOT TRAVIS)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fstack-protector-strong -static-libasan")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${TARGET}_SRC
|
||||
mdbx.h
|
||||
src/bits.h
|
||||
src/defs.h
|
||||
src/lck-linux.c
|
||||
src/mdbx.c
|
||||
src/osal.c
|
||||
src/osal.h
|
||||
src/version.c
|
||||
)
|
||||
|
||||
add_library(${TARGET}_STATIC STATIC
|
||||
${${TARGET}_SRC}
|
||||
)
|
||||
|
||||
add_library(${TARGET} ALIAS ${TARGET}_STATIC)
|
||||
|
||||
add_library(${TARGET}_SHARED SHARED
|
||||
${${TARGET}_SRC}
|
||||
)
|
||||
|
||||
set_target_properties(${TARGET}_SHARED PROPERTIES
|
||||
VERSION ${MDBX_VERSION_STRING}
|
||||
SOVERSION ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}
|
||||
OUTPUT_NAME ${TARGET}
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
)
|
||||
|
||||
set_target_properties(${TARGET}_STATIC PROPERTIES
|
||||
VERSION ${MDBX_VERSION_STRING}
|
||||
SOVERSION ${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}
|
||||
OUTPUT_NAME ${TARGET}
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
)
|
||||
|
||||
target_include_directories(${TARGET}_STATIC PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(${TARGET}_SHARED PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(${TARGET}_STATIC ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(${TARGET}_SHARED ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(${TARGET}_STATIC rt)
|
||||
target_link_libraries(${TARGET}_SHARED rt)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${TARGET}_STATIC DESTINATION ${CMAKE_INSTALL_PREFIX}/lib64 COMPONENT mdbx)
|
||||
install(TARGETS ${TARGET}_SHARED DESTINATION ${CMAKE_INSTALL_PREFIX}/lib64 COMPONENT mdbx)
|
||||
install(FILES mdbx.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include COMPONENT mdbx-devel)
|
||||
|
||||
add_subdirectory(src/tools)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(test/pcrf)
|
||||
add_subdirectory(tutorial)
|
||||
|
||||
##############################################################################
|
||||
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
set(CPACK_RPM_COMPONENT_INSTALL ON)
|
||||
|
||||
# Version
|
||||
if (NOT "$ENV{BUILD_NUMBER}" STREQUAL "")
|
||||
set(CPACK_PACKAGE_RELEASE $ENV{BUILD_NUMBER})
|
||||
else()
|
||||
if (NOT "$ENV{CI_PIPELINE_ID}" STREQUAL "")
|
||||
set(CPACK_PACKAGE_RELEASE $ENV{CI_PIPELINE_ID})
|
||||
else()
|
||||
set(CPACK_PACKAGE_RELEASE 1)
|
||||
endif()
|
||||
endif()
|
||||
set(CPACK_RPM_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE})
|
||||
|
||||
set(CPACK_PACKAGE_VERSION ${MDBX_VERSION_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_FULL ${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE})
|
||||
|
||||
set(CPACK_RPM_mdbx-devel_PACKAGE_REQUIRES "mdbx = ${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true")
|
||||
set(CPACK_RPM_mdbx_PACKAGE_NAME mdbx)
|
||||
set(CPACK_RPM_mdbx-devel_PACKAGE_NAME mdbx-devel)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The revised and extended descendant of Symas LMDB")
|
||||
|
||||
set(CPACK_PACKAGE_VENDOR "???")
|
||||
set(CPACK_PACKAGE_CONTACT "Vladimir Romanov")
|
||||
set(CPACK_PACKAGE_RELOCATABLE false)
|
||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "")
|
||||
set(CPACK_RPM_PACKAGE_GROUP "Applications/Database")
|
||||
|
||||
set(CPACK_RPM_mdbx_FILE_NAME "${CPACK_RPM_mdbx_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_FULL}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm")
|
||||
set(CPACK_RPM_mdbx-devel_FILE_NAME "${CPACK_RPM_mdbx-devel_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_FULL}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm")
|
||||
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
|
||||
/usr/local
|
||||
/usr/local/bin
|
||||
/usr/local/lib64
|
||||
/usr/local/include
|
||||
/usr/local/man
|
||||
/usr/local/man/man1
|
||||
)
|
||||
|
||||
include(CPack)
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
CONFIG=$1
|
||||
|
||||
if [[ -z "${CONFIG}" ]]; then
|
||||
CONFIG=Debug
|
||||
fi
|
||||
if [[ -r /opt/rh/devtoolset-6/enable ]]; then
|
||||
source /opt/rh/devtoolset-6/enable
|
||||
fi
|
||||
#rm -f -r build || true
|
||||
mkdir -p cmake-build-${CONFIG}
|
||||
pushd cmake-build-${CONFIG} &> /dev/null
|
||||
if [[ ! -r Makefile ]]; then
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${CONFIG}
|
||||
fi
|
||||
make -j8 || exit 1
|
||||
popd &> /dev/null
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
CONFIG=$1
|
||||
|
||||
if [[ -z "${CONFIG}" ]]; then
|
||||
CONFIG=Debug
|
||||
fi
|
||||
|
||||
DIRNAME=`dirname ${BASH_SOURCE[0]}`
|
||||
DIRNAME=`readlink --canonicalize ${DIRNAME}`
|
||||
|
||||
if [[ -r /opt/rh/devtoolset-6/enable ]]; then
|
||||
source /opt/rh/devtoolset-6/enable
|
||||
fi
|
||||
|
||||
mkdir -p cmake-build-${CONFIG}
|
||||
pushd cmake-build-${CONFIG} &> /dev/null
|
||||
if [[ ! -r Makefile ]]; then
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${CONFIG}
|
||||
fi
|
||||
rm -f *.rpm
|
||||
make -j8 package || exit 1
|
||||
rm -f *-Unspecified.rpm
|
||||
popd &> /dev/null
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
##
|
||||
## Copyright 2019 Leonid Yuriev <leo@yuriev.ru>
|
||||
## and other libmdbx authors: please see AUTHORS file.
|
||||
## All rights reserved.
|
||||
##
|
||||
## Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted only as authorized by the OpenLDAP
|
||||
## Public License.
|
||||
##
|
||||
## A copy of this license is available in the file LICENSE in the
|
||||
## top-level directory of the distribution or, alternatively, at
|
||||
## <http://www.OpenLDAP.org/license.html>.
|
||||
##
|
||||
|
||||
# Get version
|
||||
fetch_version(MDBX "${CMAKE_CURRENT_SOURCE_DIR}/../VERSION")
|
||||
message(STATUS "libmdbx version is ${MDBX_VERSION}")
|
||||
|
||||
if(MDBX_ALLOY_MODE)
|
||||
set(LIBMDBX_SOURCES alloy.c)
|
||||
else()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
set(LIBMDBX_OSAL windows)
|
||||
else()
|
||||
set(LIBMDBX_OSAL posix)
|
||||
endif()
|
||||
set(LIBMDBX_SOURCES
|
||||
elements/defs.h elements/internals.h elements/osal.h
|
||||
elements/core.c elements/osal.c elements/lck-${LIBMDBX_OSAL}.c)
|
||||
endif()
|
||||
list(APPEND LIBMDBX_SOURCES ../mdbx.h
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/elements/version.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/elements/config.h")
|
||||
|
||||
if(MDBX_BUILD_SHARED_LIBRARY)
|
||||
add_library(mdbx SHARED ${LIBMDBX_SOURCES})
|
||||
target_compile_definitions(mdbx PRIVATE LIBMDBX_EXPORTS INTERFACE LIBMDBX_IMPORTS)
|
||||
set(MDBX_LIBDEP_MODE PRIVATE)
|
||||
else()
|
||||
add_library(mdbx STATIC ${LIBMDBX_SOURCES})
|
||||
set(MDBX_LIBDEP_MODE PUBLIC)
|
||||
endif()
|
||||
|
||||
if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION))
|
||||
set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
if(MSVC)
|
||||
if(NOT MSVC_LIB_EXE)
|
||||
# Find lib.exe
|
||||
get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME)
|
||||
string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME})
|
||||
find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE})
|
||||
endif()
|
||||
if(MSVC_LIB_EXE)
|
||||
message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}")
|
||||
set(MDBX_NTDLL_EXTRA_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib)
|
||||
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
|
||||
COMMENT "Create extra-import-library for ntdll.dll"
|
||||
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
|
||||
COMMAND ${MSVC_LIB_EXE} /def:"${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
|
||||
else()
|
||||
message(SEND_ERROR "MSVC's lib tool not found")
|
||||
endif()
|
||||
elseif(MINGW OR MINGW64)
|
||||
if(NOT DLLTOOL)
|
||||
# Find dlltool
|
||||
get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME)
|
||||
string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME})
|
||||
find_program(DLLTOOL NAMES ${DLLTOOL_NAME})
|
||||
endif()
|
||||
if(DLLTOOL)
|
||||
message(STATUS "Found dlltool: ${DLLTOOL}")
|
||||
set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a")
|
||||
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
|
||||
COMMENT "Create extra-import-library for ntdll.dll"
|
||||
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
|
||||
COMMAND ${DLLTOOL} -d "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
|
||||
else()
|
||||
message(SEND_ERROR "dlltool not found")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll.lib)
|
||||
if(MDBX_NTDLL_EXTRA_IMPLIB)
|
||||
# LY: Sometimes Cmake requires a nightmarish magic for simple things.
|
||||
# 1) create a target out of the library compilation result
|
||||
add_custom_target(ntdll_extra_target DEPENDS ${MDBX_NTDLL_EXTRA_IMPLIB})
|
||||
# 2) create an library target out of the library compilation result
|
||||
add_library(ntdll_extra STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(ntdll_extra ntdll_extra_target)
|
||||
# 3) specify where the library is (and where to find the headers)
|
||||
set_target_properties(ntdll_extra
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${MDBX_NTDLL_EXTRA_IMPLIB})
|
||||
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll_extra)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(mdbx PROPERTIES
|
||||
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>
|
||||
C_STANDARD ${MDBX_C_STANDARD} C_STANDARD_REQUIRED ON
|
||||
PUBLIC_HEADER "../mdbx.h")
|
||||
|
||||
if(CC_HAS_FASTMATH)
|
||||
target_compile_options(mdbx PRIVATE "-ffast-math")
|
||||
endif()
|
||||
if(BUILD_FOR_NATIVE_CPU AND CC_HAS_ARCH_NATIVE)
|
||||
target_compile_options(mdbx PUBLIC "-march=native")
|
||||
endif()
|
||||
if(CC_HAS_VISIBILITY)
|
||||
target_compile_options(mdbx PRIVATE "-fvisibility=hidden")
|
||||
endif()
|
||||
|
||||
install(TARGETS mdbx
|
||||
LIBRARY DESTINATION lib COMPONENT runtime
|
||||
RUNTIME DESTINATION bin COMPONENT runtime
|
||||
ARCHIVE DESTINATION lib/static COMPONENT devel
|
||||
PUBLIC_HEADER DESTINATION include
|
||||
INCLUDES DESTINATION include COMPONENT devel)
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# library build info (used in library version output)
|
||||
#
|
||||
set(MDBX_BUILD_FLAGS "")
|
||||
|
||||
# append cmake's build-type flags and defines
|
||||
if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_C_DEFINES_${CMAKE_BUILD_TYPE_UPPERCASE}})
|
||||
endif()
|
||||
|
||||
# append linker dll's options
|
||||
if(LIBMDBX_TYPE STREQUAL "SHARED")
|
||||
list(APPEND MDBX_BUILD_FLAGS ${CMAKE_SHARED_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
# get definitions
|
||||
get_target_property(defs_list mdbx COMPILE_DEFINITIONS)
|
||||
if(defs_list)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${defs_list})
|
||||
endif()
|
||||
|
||||
# get target compile options
|
||||
get_target_property(options_list mdbx COMPILE_OPTIONS)
|
||||
if(options_list)
|
||||
list(APPEND MDBX_BUILD_FLAGS ${options_list})
|
||||
endif()
|
||||
|
||||
list(REMOVE_DUPLICATES MDBX_BUILD_FLAGS)
|
||||
string(REPLACE ";" " " MDBX_BUILD_FLAGS "${MDBX_BUILD_FLAGS}")
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
# add dynamic part via per-configuration define
|
||||
message(STATUS "MDBX Compile Flags: ${MDBX_BUILD_FLAGS} <AND CONFIGURATION DEPENDENT>")
|
||||
add_definitions(-DMDBX_BUILD_FLAGS_CONFIG="$<$<CONFIG:Debug>:${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_DEFINES_DEBUG}>$<$<CONFIG:Release>:${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_DEFINES_RELEASE}>$<$<CONFIG:RelWithDebInfo>:${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_DEFINES_RELWITHDEBINFO}>$<$<CONFIG:MinSizeRel>:${CMAKE_C_FLAGS_MINSIZEREL} ${CMAKE_C_DEFINES_MINSIZEREL}>")
|
||||
else()
|
||||
message(STATUS "MDBX Compile Flags: ${MDBX_BUILD_FLAGS}")
|
||||
endif()
|
||||
|
||||
# get compiler info
|
||||
execute_process(COMMAND sh -c "${CMAKE_C_COMPILER} --version | head -1"
|
||||
OUTPUT_VARIABLE MDBX_BUILD_COMPILER
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE rc)
|
||||
if(rc OR NOT MDBX_BUILD_COMPILER)
|
||||
string(STRIP "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}" MDBX_BUILD_COMPILER)
|
||||
endif()
|
||||
|
||||
# make a build-target triplet
|
||||
if(CMAKE_C_COMPILER_TARGET)
|
||||
set(MDBX_BUILD_TARGET "${CMAKE_C_COMPILER_TARGET}")
|
||||
elseif(CMAKE_C_PLATFORM_ID AND NOT CMAKE_C_PLATFORM_ID STREQUAL CMAKE_SYSTEM_NAME)
|
||||
string(STRIP "${CMAKE_C_PLATFORM_ID}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_LIBRARY_ARCHITECTURE)
|
||||
string(STRIP "${CMAKE_LIBRARY_ARCHITECTURE}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_GENERATOR_PLATFORM AND NOT CMAKE_C_PLATFORM_ID STREQUAL CMAKE_SYSTEM_NAME)
|
||||
string(STRIP "${CMAKE_GENERATOR_PLATFORM}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
elseif(CMAKE_SYSTEM_ARCH)
|
||||
string(STRIP "${CMAKE_SYSTEM_ARCH}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
else()
|
||||
string(STRIP "${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}" MDBX_BUILD_TARGET)
|
||||
endif()
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
add_definitions(-DMDBX_BUILD_CONFIG="$<CONFIG>")
|
||||
else()
|
||||
set(MDBX_BUILD_CONFIG ${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
# options
|
||||
string(TIMESTAMP MDBX_BUILD_TIMESTAMP UTC)
|
||||
set(options VERSION C_COMPILER CXX_COMPILER)
|
||||
foreach(item IN LISTS options)
|
||||
if(DEFINED ${item})
|
||||
set(value "${${item}}")
|
||||
elseif(DEFINED MDBX_${item})
|
||||
set(item MDBX_${item})
|
||||
set(value "${${item}}")
|
||||
elseif(DEFINED CMAKE_${item})
|
||||
set(item CMAKE_${item})
|
||||
set(value "${${item}}")
|
||||
else()
|
||||
set(value "undefined")
|
||||
endif()
|
||||
message(STATUS "${item}: ${value}")
|
||||
endforeach(item)
|
||||
|
||||
# generate version and config files
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/elements/version.c.in"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/elements/version.c" ESCAPE_QUOTES)
|
||||
|
||||
file(SHA256 "${CMAKE_CURRENT_SOURCE_DIR}/elements/version.c" MDBX_SOURCERY_DIGEST)
|
||||
string(MAKE_C_IDENTIFIER "${MDBX_GIT_DESCRIBE}" MDBX_SOURCERY_SUFFIX)
|
||||
set(MDBX_BUILD_SOURCERY "${MDBX_SOURCERY_DIGEST}_${MDBX_SOURCERY_SUFFIX}")
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/elements/config.h.in"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/elements/config.h" ESCAPE_QUOTES)
|
||||
add_definitions(-DMDBX_CONFIG_H="config.h")
|
||||
|
||||
add_subdirectory(tools)
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>. */
|
||||
|
||||
/* Amalgamated build */
|
||||
#define MDBX_ALLOY 1
|
||||
#include "elements/internals.h" /* must be included fisrt */
|
||||
|
||||
#include "elements/core.c"
|
||||
#include "elements/osal.c"
|
||||
#include "elements/version.c"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include "elements/lck-windows.c"
|
||||
#else
|
||||
#include "elements/lck-posix.c"
|
||||
#endif
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/* This is CMake-template for libmdbx's config.h
|
||||
******************************************************************************/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
|
||||
#cmakedefine HAVE_VALGRIND_MEMCHECK_H
|
||||
#cmakedefine HAS_RELAXED_CONSTEXPR
|
||||
|
||||
#cmakedefine LTO_ENABLED
|
||||
#cmakedefine MDBX_USE_VALGRIND
|
||||
#cmakedefine ENABLE_GPROF
|
||||
#cmakedefine ENABLE_GCOV
|
||||
#cmakedefine ENABLE_ASAN
|
||||
|
||||
/* Common */
|
||||
#cmakedefine01 MDBX_TXN_CHECKPID
|
||||
#cmakedefine01 MDBX_TXN_CHECKOWNER
|
||||
#cmakedefine01 MDBX_BUILD_SHARED_LIBRARY
|
||||
|
||||
/* Windows */
|
||||
#cmakedefine01 MDBX_CONFIG_MANUAL_TLS_CALLBACK
|
||||
#cmakedefine01 MDBX_AVOID_CRT
|
||||
|
||||
/* MacOS */
|
||||
#cmakedefine01 MDBX_OSX_SPEED_INSTEADOF_DURABILITY
|
||||
|
||||
/* POSIX */
|
||||
#cmakedefine01 MDBX_USE_ROBUST
|
||||
#cmakedefine01 MDBX_USE_OFDLOCKS
|
||||
#cmakedefine01 MDBX_DISABLE_GNU_SOURCE
|
||||
|
||||
/* Simulate "AUTO" values of tristate options */
|
||||
#cmakedefine MDBX_TXN_CHECKPID_AUTO
|
||||
#ifdef MDBX_TXN_CHECKPID_AUTO
|
||||
#undef MDBX_TXN_CHECKPID
|
||||
#endif
|
||||
#cmakedefine MDBX_USE_ROBUST_AUTO
|
||||
#ifdef MDBX_USE_ROBUST_AUTO
|
||||
#undef MDBX_USE_ROBUST
|
||||
#endif
|
||||
#cmakedefine MDBX_USE_OFDLOCKS_AUTO
|
||||
#ifdef MDBX_USE_OFDLOCKS_AUTO
|
||||
#undef MDBX_USE_OFDLOCKS
|
||||
#endif
|
||||
|
||||
/* Build Info */
|
||||
#cmakedefine MDBX_BUILD_TIMESTAMP "@MDBX_BUILD_TIMESTAMP@"
|
||||
#cmakedefine MDBX_BUILD_TARGET "@MDBX_BUILD_TARGET@"
|
||||
#cmakedefine MDBX_BUILD_CONFIG "@MDBX_BUILD_CONFIG@"
|
||||
#cmakedefine MDBX_BUILD_COMPILER "@MDBX_BUILD_COMPILER@"
|
||||
#cmakedefine MDBX_BUILD_FLAGS "@MDBX_BUILD_FLAGS@"
|
||||
#cmakedefine MDBX_BUILD_SOURCERY @MDBX_BUILD_SOURCERY@
|
||||
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,450 +0,0 @@
|
|||
/*
|
||||
* Copyright 2015-2019 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted only as authorized by the OpenLDAP
|
||||
* Public License.
|
||||
*
|
||||
* A copy of this license is available in the file LICENSE in the
|
||||
* top-level directory of the distribution or, alternatively, at
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
/* *INDENT-OFF* */
|
||||
/* clang-format off */
|
||||
|
||||
#ifndef __GNUC_PREREQ
|
||||
# if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define __GNUC_PREREQ(maj, min) \
|
||||
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __GNUC_PREREQ(maj, min) (0)
|
||||
# endif
|
||||
#endif /* __GNUC_PREREQ */
|
||||
|
||||
#ifndef __CLANG_PREREQ
|
||||
# ifdef __clang__
|
||||
# define __CLANG_PREREQ(maj,min) \
|
||||
((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __CLANG_PREREQ(maj,min) (0)
|
||||
# endif
|
||||
#endif /* __CLANG_PREREQ */
|
||||
|
||||
#ifndef __GLIBC_PREREQ
|
||||
# if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
|
||||
# define __GLIBC_PREREQ(maj, min) \
|
||||
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __GLIBC_PREREQ(maj, min) (0)
|
||||
# endif
|
||||
#endif /* __GLIBC_PREREQ */
|
||||
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_extension
|
||||
# define __has_extension(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_warning
|
||||
# define __has_warning(x) (0)
|
||||
#endif
|
||||
|
||||
#ifndef __has_include
|
||||
# define __has_include(x) (0)
|
||||
#endif
|
||||
|
||||
#if __has_feature(thread_sanitizer)
|
||||
# define __SANITIZE_THREAD__ 1
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer)
|
||||
# define __SANITIZE_ADDRESS__ 1
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __extern_C
|
||||
# ifdef __cplusplus
|
||||
# define __extern_C extern "C"
|
||||
# else
|
||||
# define __extern_C
|
||||
# endif
|
||||
#endif /* __extern_C */
|
||||
|
||||
#ifndef __cplusplus
|
||||
# ifndef bool
|
||||
# define bool _Bool
|
||||
# endif
|
||||
# ifndef true
|
||||
# define true (1)
|
||||
# endif
|
||||
# ifndef false
|
||||
# define false (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(nullptr) && !defined(__cplusplus) || (__cplusplus < 201103L && !defined(_MSC_VER))
|
||||
# define nullptr NULL
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef __always_inline
|
||||
# if defined(__GNUC__) || __has_attribute(__always_inline__)
|
||||
# define __always_inline __inline __attribute__((__always_inline__))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __always_inline __forceinline
|
||||
# else
|
||||
# define __always_inline
|
||||
# endif
|
||||
#endif /* __always_inline */
|
||||
|
||||
#ifndef __noinline
|
||||
# if defined(__GNUC__) || __has_attribute(__noinline__)
|
||||
# define __noinline __attribute__((__noinline__))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noinline __declspec(noinline)
|
||||
# elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
|
||||
# define __noinline inline
|
||||
# elif !defined(__INTEL_COMPILER)
|
||||
# define __noinline /* FIXME ? */
|
||||
# endif
|
||||
#endif /* __noinline */
|
||||
|
||||
#ifndef __must_check_result
|
||||
# if defined(__GNUC__) || __has_attribute(__warn_unused_result__)
|
||||
# define __must_check_result __attribute__((__warn_unused_result__))
|
||||
# else
|
||||
# define __must_check_result
|
||||
# endif
|
||||
#endif /* __must_check_result */
|
||||
|
||||
#ifndef __maybe_unused
|
||||
# if defined(__GNUC__) || __has_attribute(__unused__)
|
||||
# define __maybe_unused __attribute__((__unused__))
|
||||
# else
|
||||
# define __maybe_unused
|
||||
# endif
|
||||
#endif /* __maybe_unused */
|
||||
|
||||
#ifndef __deprecated
|
||||
# if defined(__GNUC__) || __has_attribute(__deprecated__)
|
||||
# define __deprecated __attribute__((__deprecated__))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __deprecated __declspec(deprecated)
|
||||
# else
|
||||
# define __deprecated
|
||||
# endif
|
||||
#endif /* __deprecated */
|
||||
|
||||
#if !defined(__noop) && !defined(_MSC_VER)
|
||||
# define __noop(...) do {} while(0)
|
||||
#endif /* __noop */
|
||||
|
||||
#ifndef __fallthrough
|
||||
# if __GNUC_PREREQ(7, 0) || __has_attribute(__fallthrough__)
|
||||
# define __fallthrough __attribute__((__fallthrough__))
|
||||
# else
|
||||
# define __fallthrough __noop()
|
||||
# endif
|
||||
#endif /* __fallthrough */
|
||||
|
||||
#ifndef __unreachable
|
||||
# if __GNUC_PREREQ(4,5)
|
||||
# define __unreachable() __builtin_unreachable()
|
||||
# elif defined(_MSC_VER)
|
||||
# define __unreachable() __assume(0)
|
||||
# else
|
||||
# define __unreachable() __noop()
|
||||
# endif
|
||||
#endif /* __unreachable */
|
||||
|
||||
#ifndef __prefetch
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define __prefetch(ptr) __builtin_prefetch(ptr)
|
||||
# else
|
||||
# define __prefetch(ptr) __noop(ptr)
|
||||
# endif
|
||||
#endif /* __prefetch */
|
||||
|
||||
#ifndef __noreturn
|
||||
# if defined(__GNUC__) || __has_attribute(__noreturn__)
|
||||
# define __noreturn __attribute__((__noreturn__))
|
||||
# elif defined(_MSC_VER)
|
||||
# define __noreturn __declspec(noreturn)
|
||||
# else
|
||||
# define __noreturn
|
||||
# endif
|
||||
#endif /* __noreturn */
|
||||
|
||||
#ifndef __nothrow
|
||||
# if defined(__cplusplus)
|
||||
# if __cplusplus < 201703L
|
||||
# define __nothrow throw()
|
||||
# else
|
||||
# define __nothrow noexcept(true)
|
||||
# endif /* __cplusplus */
|
||||
# elif defined(__GNUC__) || __has_attribute(__nothrow__)
|
||||
# define __nothrow __attribute__((__nothrow__))
|
||||
# elif defined(_MSC_VER) && defined(__cplusplus)
|
||||
# define __nothrow __declspec(nothrow)
|
||||
# else
|
||||
# define __nothrow
|
||||
# endif
|
||||
#endif /* __nothrow */
|
||||
|
||||
#ifndef __pure_function
|
||||
/* Many functions have no effects except the return value and their
|
||||
* return value depends only on the parameters and/or global variables.
|
||||
* Such a function can be subject to common subexpression elimination
|
||||
* and loop optimization just as an arithmetic operator would be.
|
||||
* These functions should be declared with the attribute pure. */
|
||||
# if defined(__GNUC__) || __has_attribute(__pure__)
|
||||
# define __pure_function __attribute__((__pure__))
|
||||
# else
|
||||
# define __pure_function
|
||||
# endif
|
||||
#endif /* __pure_function */
|
||||
|
||||
#ifndef __const_function
|
||||
/* Many functions do not examine any values except their arguments,
|
||||
* and have no effects except the return value. Basically this is just
|
||||
* slightly more strict class than the PURE attribute, since function
|
||||
* is not allowed to read global memory.
|
||||
*
|
||||
* Note that a function that has pointer arguments and examines the
|
||||
* data pointed to must not be declared const. Likewise, a function
|
||||
* that calls a non-const function usually must not be const.
|
||||
* It does not make sense for a const function to return void. */
|
||||
# if defined(__GNUC__) || __has_attribute(__const__)
|
||||
# define __const_function __attribute__((__const__))
|
||||
# else
|
||||
# define __const_function
|
||||
# endif
|
||||
#endif /* __const_function */
|
||||
|
||||
#ifndef __hidden
|
||||
# if defined(__GNUC__) || __has_attribute(__visibility__)
|
||||
# define __hidden __attribute__((__visibility__("hidden")))
|
||||
# else
|
||||
# define __hidden
|
||||
# endif
|
||||
#endif /* __hidden */
|
||||
|
||||
#ifndef __optimize
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__clang__) && !__has_attribute(__optimize__)
|
||||
# define __optimize(ops)
|
||||
# elif defined(__GNUC__) || __has_attribute(__optimize__)
|
||||
# define __optimize(ops) __attribute__((__optimize__(ops)))
|
||||
# else
|
||||
# define __optimize(ops)
|
||||
# endif
|
||||
# else
|
||||
# define __optimize(ops)
|
||||
# endif
|
||||
#endif /* __optimize */
|
||||
|
||||
#ifndef __hot
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__e2k__)
|
||||
# define __hot __attribute__((__hot__)) __optimize(3)
|
||||
# elif defined(__clang__) && !__has_attribute(__hot_) \
|
||||
&& __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
|
||||
/* just put frequently used functions in separate section */
|
||||
# define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
|
||||
# elif defined(__GNUC__) || __has_attribute(__hot__)
|
||||
# define __hot __attribute__((__hot__)) __optimize("O3")
|
||||
# else
|
||||
# define __hot __optimize("O3")
|
||||
# endif
|
||||
# else
|
||||
# define __hot
|
||||
# endif
|
||||
#endif /* __hot */
|
||||
|
||||
#ifndef __cold
|
||||
# if defined(__OPTIMIZE__)
|
||||
# if defined(__e2k__)
|
||||
# define __cold __attribute__((__cold__)) __optimize(1)
|
||||
# elif defined(__clang__) && !__has_attribute(cold) \
|
||||
&& __has_attribute(__section__) && (defined(__linux__) || defined(__gnu_linux__))
|
||||
/* just put infrequently used functions in separate section */
|
||||
# define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
|
||||
# elif defined(__GNUC__) || __has_attribute(cold)
|
||||
# define __cold __attribute__((__cold__)) __optimize("Os")
|
||||
# else
|
||||
# define __cold __optimize("Os")
|
||||
# endif
|
||||
# else
|
||||
# define __cold
|
||||
# endif
|
||||
#endif /* __cold */
|
||||
|
||||
#ifndef __flatten
|
||||
# if defined(__OPTIMIZE__) && (defined(__GNUC__) || __has_attribute(__flatten__))
|
||||
# define __flatten __attribute__((__flatten__))
|
||||
# else
|
||||
# define __flatten
|
||||
# endif
|
||||
#endif /* __flatten */
|
||||
|
||||
#ifndef likely
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__COVERITY__)
|
||||
# define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
# else
|
||||
# define likely(x) (x)
|
||||
# endif
|
||||
#endif /* likely */
|
||||
|
||||
#ifndef unlikely
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__COVERITY__)
|
||||
# define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
# else
|
||||
# define unlikely(x) (x)
|
||||
# endif
|
||||
#endif /* unlikely */
|
||||
|
||||
/* Workaround for Coverity Scan */
|
||||
#if defined(__COVERITY__) && __GNUC_PREREQ(7, 0) && !defined(__cplusplus)
|
||||
typedef float _Float32;
|
||||
typedef double _Float32x;
|
||||
typedef double _Float64;
|
||||
typedef long double _Float64x;
|
||||
typedef float _Float128 __attribute__((__mode__(__TF__)));
|
||||
typedef __complex__ float __cfloat128 __attribute__ ((__mode__ (__TC__)));
|
||||
typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
|
||||
#endif /* Workaround for Coverity Scan */
|
||||
|
||||
#ifndef __printf_args
|
||||
# if defined(__GNUC__) || __has_attribute(__format__)
|
||||
# define __printf_args(format_index, first_arg) \
|
||||
__attribute__((__format__(printf, format_index, first_arg)))
|
||||
# else
|
||||
# define __printf_args(format_index, first_arg)
|
||||
# endif
|
||||
#endif /* __printf_args */
|
||||
|
||||
#ifndef __anonymous_struct_extension__
|
||||
# if defined(__GNUC__)
|
||||
# define __anonymous_struct_extension__ __extension__
|
||||
# else
|
||||
# define __anonymous_struct_extension__
|
||||
# endif
|
||||
#endif /* __anonymous_struct_extension__ */
|
||||
|
||||
#ifndef __Wpedantic_format_voidptr
|
||||
static __inline const void* __pure_function
|
||||
__Wpedantic_format_voidptr(const void* ptr) {return ptr;}
|
||||
# define __Wpedantic_format_voidptr(ARG) __Wpedantic_format_voidptr(ARG)
|
||||
#endif /* __Wpedantic_format_voidptr */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(MDBX_USE_VALGRIND)
|
||||
# include <valgrind/memcheck.h>
|
||||
# ifndef VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE
|
||||
/* LY: available since Valgrind 3.10 */
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# endif
|
||||
#elif !defined(RUNNING_ON_VALGRIND)
|
||||
# define VALGRIND_CREATE_MEMPOOL(h,r,z)
|
||||
# define VALGRIND_DESTROY_MEMPOOL(h)
|
||||
# define VALGRIND_MEMPOOL_TRIM(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_ALLOC(h,a,s)
|
||||
# define VALGRIND_MEMPOOL_FREE(h,a)
|
||||
# define VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
|
||||
# define VALGRIND_MAKE_MEM_NOACCESS(a,s)
|
||||
# define VALGRIND_MAKE_MEM_DEFINED(a,s)
|
||||
# define VALGRIND_MAKE_MEM_UNDEFINED(a,s)
|
||||
# define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(a,s)
|
||||
# define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,s) (0)
|
||||
# define VALGRIND_CHECK_MEM_IS_DEFINED(a,s) (0)
|
||||
# define RUNNING_ON_VALGRIND (0)
|
||||
#endif /* MDBX_USE_VALGRIND */
|
||||
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
# include <sanitizer/asan_interface.h>
|
||||
#elif !defined(ASAN_POISON_MEMORY_REGION)
|
||||
# define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
#endif /* __SANITIZE_ADDRESS__ */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ARRAY_LENGTH
|
||||
# ifdef __cplusplus
|
||||
template <typename T, size_t N>
|
||||
char (&__ArraySizeHelper(T (&array)[N]))[N];
|
||||
# define ARRAY_LENGTH(array) (sizeof(::__ArraySizeHelper(array)))
|
||||
# else
|
||||
# define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
|
||||
# endif
|
||||
#endif /* ARRAY_LENGTH */
|
||||
|
||||
#ifndef ARRAY_END
|
||||
# define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
|
||||
#endif /* ARRAY_END */
|
||||
|
||||
#ifndef STRINGIFY
|
||||
# define STRINGIFY_HELPER(x) #x
|
||||
# define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||
#endif /* STRINGIFY */
|
||||
|
||||
#define CONCAT(a,b) a##b
|
||||
#define XCONCAT(a,b) CONCAT(a,b)
|
||||
|
||||
#ifndef offsetof
|
||||
# define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
#endif /* offsetof */
|
||||
|
||||
#ifndef container_of
|
||||
# define container_of(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||
#endif /* container_of */
|
||||
|
||||
#define MDBX_TETRAD(a, b, c, d) \
|
||||
((uint32_t)(a) << 24 | (uint32_t)(b) << 16 | (uint32_t)(c) << 8 | (d))
|
||||
|
||||
#define MDBX_STRING_TETRAD(str) MDBX_TETRAD(str[0], str[1], str[2], str[3])
|
||||
|
||||
#define FIXME "FIXME: " __FILE__ ", " STRINGIFY(__LINE__)
|
||||
|
||||
#ifndef STATIC_ASSERT_MSG
|
||||
# if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| __has_feature(c_static_assert)
|
||||
# define STATIC_ASSERT_MSG(expr, msg) _Static_assert(expr, msg)
|
||||
# elif defined(static_assert)
|
||||
# define STATIC_ASSERT_MSG(expr, msg) static_assert(expr, msg)
|
||||
# elif defined(_MSC_VER)
|
||||
# include <crtdbg.h>
|
||||
# define STATIC_ASSERT_MSG(expr, msg) _STATIC_ASSERT(expr)
|
||||
# else
|
||||
# define STATIC_ASSERT_MSG(expr, msg) switch (0) {case 0:case (expr):;}
|
||||
# endif
|
||||
#endif /* STATIC_ASSERT */
|
||||
|
||||
#ifndef STATIC_ASSERT
|
||||
# define STATIC_ASSERT(expr) STATIC_ASSERT_MSG(expr, #expr)
|
||||
#endif
|
||||
|
||||
/* *INDENT-ON* */
|
||||
/* clang-format on */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue