2nd step Put
#include <iostream>
#include <string.h>
#include "rocksdb/db.h"
DB* db;
Options options;
options.create_if_missing = true;
Status s = DB::Open(options, <DBPath>, &db);
assert(s.ok());
//read image
FILE* file_in;
int fopen_err = fopen_s(&file_in, <input_file_path>, "rb");
if (fopen_err != 0) {
printf(input_file_path, "%s is not valid");;
}
fseek(file_in, 0, SEEK_END);
long int file_size = ftell(file_in);
rewind(file_in);
//malloc buffer
char* buffer = (char*)malloc(file_size);
if (buffer == NULL) { printf("Memory Error!!"); }
fread(buffer, file_size, 1, file_in);
//main func
db->Put(WriteOptions(), file_key, buffer);
assert(s.ok());
fclose(file_in);
free(buffer);
buffer = NULL;
delete db;
3rd step Get
#include <iostream>
#include <string.h>
#include "rocksdb/db.h"
DB* db;
Options options;
options.create_if_missing = true;
Status s = DB::Open(options, <DBPath>, &db);
assert(s.ok());
//main func
std::string file_data
s = db->Get(ReadOptions(), file_key, &file_data);
assert(s.ok());
//convert std::string to char*
char* buffer = (char*)malloc(file_data.size() + 1);
std::copy(file_data.begin(), file_data.end(), buffer);
//restore image
FILE* test;
fopen_s(&test, "test.jpg", "wb");
fwrite(buffer, file_data.size(), 1, test);
fclose(test);
free(buffer);
delete db;
The output image is not valid, and if I convert jpg to txt, I only get "???".
I tried on BerkeleyDB in the same process, and I succeed to restore image.(I think it's because of Dbt class of BerkeleyDB) I don't know where the data get crashed. Did I missed some options or process...?
char* buffer = ...
db->Put(WriteOptions(), file_key, buffer);
How is RocksDB supposed to know the length of the buffer? When passing in a char*
here, it is assumed to be a nul-terminated C string using the Slice(char *)
implicit conversion. Nul-terminated C strings cannot be used for binary data because the data will be cut off at the first zero byte.
Although some RocksDB APIs are not up to modern C++ standards (for API compatibility), it is written for use with C++. Nul-terminated char *
, FILE
, fseek
etc. are from C and cause lots of difficulty when attempting to interact with C++. If buffer
were std::string
, this bug would be fixed because the Slice(std::string)
implicit conversion is very safe.
Other bugs:
s
for the db->Put
printf
DB::Close(db)
before delete to check status, as there could be a background errorfread
Performance/clarity issue:
char *buffer
and copy in std::string file_data
to it. file_data.data()
and file_data.size()
give you access to the underlying char buffer if needed (but using C++ APIs is better).