Я хочу использовать leveldb в моем чистом проекте С#.
У меня есть googled для версии С# leveldb, но не повезло.
Кто-нибудь может сказать мне, где я могу найти версию leveldb на С#?
Спасибо
Я хочу использовать leveldb в моем чистом проекте С#.
У меня есть googled для версии С# leveldb, но не повезло.
Кто-нибудь может сказать мне, где я могу найти версию leveldb на С#?
Спасибо
Не то, что я знаю, но я использовал его в своем проекте С#. Если вы знакомы с С++, тогда вы можете создать свою собственную оболочку CLI (не должно быть столько проблем), создать ее как DLL, а затем вы можете загрузить эту DLL в свой проект С#, как и любую другую ссылку на сборку.
Существует оконный порт для leveldb, и немного сложно получить его в Visual Studio, но если у вас возникли проблемы, я могу загрузить свою Visual Studio 2010 решение (что составляет 75% от битвы) со всей настройкой и готовностью к построению (кроме оболочки CLI). Я могу поставить его на github или что-то еще, что я на самом деле планирую делать в любом случае, но я ускорю его для вас.
Как я уже сказал, я использовал этот подход для своего проекта С#, и он отлично работает. Однако, если у вас действительно высокие требования к производительности, я бы рекомендовал доработать "работу", чтобы уменьшить P/Invokes.
Обратите внимание, что я не скомпилировал этот код, но я просто разместил его в качестве примера. Ваш заголовочный файл может выглядеть так:
#pragma once
#include <exception>
#include "leveldb\db.h"
using namespace System::Runtime::InteropServices;
// Create the namespace
namespace LevelDBWrapperNS
{
// Note that size_t changes depending on the target platform of your build:
// for 32-bit builds, size_t is a 32-bit unsigned integer.
// for 64-bit builds, size_t is a 64-bit unsigned integer.
// There is no size_t equivalent in C#, but there are ways to
// mimic the same behavior. Alternately, you can change the
// size_t to unsigned long for 32-bit builds or unsigned long long (64-bit)
// Declare the leveldb wrapper
public ref class LevelDBWrapper
{
private:
leveldb::DB* _db;
public:
LevelDBWrapper(const std::string dataDirectory);
~LevelDBWrapper();
// A get method which given a key, puts data in the value array
// and sets the valueSize according to the size of the data it
// allocated. Note: you will have to deallocate the data in C#
void Get(const char* key, const size_t keySize, char* value, size_t &valueSize);
// A put method which takes in strings instead of char*
bool Put(const std::string key, const std::string value);
// A put method which takes in char* pointers
bool Put(const char* key, const size_t keySize, const char* value, const size_t valueSize);
// A delete method
bool Delete(const char* key, const size_t keySize);
private:
void Open(const char* dataDirectory);
};
}
Ваш файл cpp будет находиться по строкам:
#include "LevelDBWrapper.h"
// Use the same namespace as the header
namespace LevelDBWrapperNS
{
LevelDBWrapper::LevelDBWrapper(const std::string dataDirectory)
{
Open(dataDirectory.c_str());
}
LevelDBWrapper::~LevelDBWrapper()
{
if(_db!=NULL)
{
delete _db;
_db= NULL;
}
// NOTE: don't forget to delete the block cache too!!!
/*if(options.block_cache != NULL)
{
delete options.block_cache;
options.block_cache = NULL;
}*/
}
bool LevelDBWrapper::Put(const char* key, const size_t keySize, const char* value, const size_t valueSize)
{
leveldb::Slice sKey(key, keySize);
leveldb::Slice sValue(value, valueSize);
return _db->Put(leveldb::WriteOptions(), sKey, sValue).ok();
}
void LevelDBWrapper::Open(const char* dataDirectory)
{
leveldb::Options options;
// Create a database environment. This will enable caching between
// separate calls (and improve performance). This also enables
// the db_stat.exe command which allows cache tuning. Open
// transactional environment leveldb::Options options;
options.create_if_missing = true;
// Open the database if it exists
options.error_if_exists = false;
// 64 Mb read cache
options.block_cache = leveldb::NewLRUCache(64 * 1024 * 1024);
// Writes will be flushed every 32 Mb
options.write_buffer_size = 32 * 1024 * 1024;
// If you do a lot of bulk operations it may be good to increase the
// block size to a 64k block size. A power of 2 block size also
// also improves the compression rate when using Snappy.
options.block_size = 64 * 1024;
options.max_open_files = 500;
options.compression = leveldb::kNoCompression;
_db = NULL;
// Open the database
leveldb::Status status = leveldb::DB::Open(options, dataDirectory, &_db);
// Check if there was a failure
if(!status.ok())
{
// The database failed to open!
if(status.ToString().find("partial record without end")!=std::string::npos)
{
// Attempting to recover the database...
status = leveldb::RepairDB(dataDirectory, options);
if(status.ok())
{
// Successfully recovered the database! Attempting to reopen...
status = leveldb::DB::Open( options, dataDirectory, &_db);
}
else
{
// Failed to recover the database!
}
}
// Throw an exception if the failure was unrecoverable!
if(!status.ok())
{
throw std::runtime_error(std::string("Unable to open: ") + std::string(dataDirectory) +
std::string(" ") + status.ToString());
}
}
}
}
Это должно помочь вам в правильном направлении.
ОК, Get будет выглядеть так:
// Returns a buffer containing the data and sets the bufferLen.
// The user must specify the key and the length of the key so a slice
// can be constructed and sent to leveldb.
const unsigned char* Get(const char* key, const size_t keyLength, [Out]size_t %bufferLen);
Источник находится по строкам:
const unsigned char* LevelDBWrapper::Get(const char* key, const size_t keyLength, [Out]size_t %bufferLen)
{
unsigned char* buffer = NULL;
std::string value;
leveldb::Status s = db->Get(leveldb::ReadOptions(), Slice(key, keyLength), &value);
if(s.ok())
{
// we found the key, so set the buffer length
bufferLen = value.size();
// initialize the buffer
buffer = new unsigned char[bufferLen];
// set the buffer
memset(buffer, 0, bufferLen);
// copy the data
memcpy(memcpy((void*)(buffer), value.c_str(), bufferLen);
}
else
{
// The buffer length is 0 because a key was not found
bufferLen = 0;
}
return buffer;
}
Обратите внимание, что разные данные могут иметь различную кодировку, поэтому я считаю, что самый безопасный способ передачи данных между вашим неуправляемым и управляемым кодом - использовать указатели и UnmanagedMemoryStream
. Вот как вы получите данные, связанные с ключом на С#:
UInt32 bufferLen = 0;
byte* buffer = dbInstance.Get(key, keyLength, out bufferLen);
UnmanagedMemoryStream ums = new UnmanagedMemoryStream(buffer, (Int32)bufferLen, (Int32)bufferLen, FileAccess.Read);
// Create a byte array to hold data from unmanaged memory.
byte[] data = new byte [bufferLen];
// Read from unmanaged memory to the byte array.
readStream.Read(data , 0, bufferLen);
// Don't forget to free the block of unmanaged memory!!!
Marshal.FreeHGlobal(buffer);
Опять же, я не скомпилировал или не запустил код, но он должен получить вас на правильном пути.
Насколько я вижу, вы также можете использовать LMDB (база данных с привязкой к карте молнии, http://symas.com/mdb/) который кажется весьма похожим на LevelDB, а также поставляется с .Net-обложкой (https://github.com/ilyalukyanov/Lightning.NET) Не знаю, как хорошо он работает, хотя еще не использовал его...
Я не использовал его, но я вижу leveldb-sharp.
Я не знаю эту историю здесь, но там этот проект на официальной странице официального Rx-Js здесь.