Jeong Hwan Im
Jeong Hwan Im

Reputation: 3

abort() has been called while LevelDB PUT()

I'm trying to put() binary data of large scale files into the leveldb using c++ library. While put() operation working on the leveldb warning abort() has been called is generated if I execute my code.

FILE* file;
WriteOptions woptions;
woptions.sync = true'
DB* db;
Options options;
options.create_if_missing = true;

DBPATH.assign(DBName);
char key = '1';

Status s = DB::Open(options,DBPATH,&db);
assert(status.ok());
fopen_s(&file, "target.jpg", "rb");
fseek(file, 0, SEEK_END);
long long int size = ftell(file);
rewind(file);

char* buffer = (char*)calloc(1, size);
if(buffer == NULL) printf("mem error\n");
fread(buffer, size, 1, file);

Slice slice(buffer, size + 1);
Slice key_in(key, sizeof(char)+1);
status = db->Put(woptions, key, slice);
assert(status.ok());

free(buffer);
slice.clear();
key.clear();
fclose(file);
delete db;

I've tried to print the status to figure out what's the problem. But before printing status, the abort() message pops out. So I think there must be some problem in PUT(). Do I need to change config or any other envs? Or is there the size limitation of handling data exist on leveldb...? I tried berkeleydb and rocksdb in the same way,but no warning message popped. I looked up the doc of each DBs. And I can't find how to handle BLOBs at leveldb doc unlike other DBs. Now I wonder if the leveldb supports the BLOBs.....!

Upvotes: 0

Views: 137

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 118097

After looking at the LevelDB API I think this is what's wrong:

char key = '1';
// ...
Slice slice(buffer, size + 1);             // + 1 is wrong
slice key_in(key, sizeof(char)+1);         // `key_in` is invalid and +1 is wrong
status = db->Put(woptions, key, slice);    // and `key_in` is unused

The Key you use is not a Slice, it's a char.

If you only want a single char for the Key:

char key = '1';
// ...
Slice slice(buffer, size);                 // correct size
Slice key_in(&key, sizeof key);            // take the address and size of the key
status = db->Put(woptions, key_in, slice); // and use `key_in`

Alternatively, create your Key Slice from a char*:

char key[] = "1";
// ...
Slice slice(buffer, size);                 // correct size
Slice key_in(key);                         // `key_in` created from C string
status = db->Put(woptions, key_in, slice); // and use `key_in`

I also suggest simplifying the code. Don't use calloc. Use a std::vector<char> instead.

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>

// Read the whole file into a vector<char>
std::vector<char> get_file_content(const std::string& filename) {
    std::ifstream is(filename, std::ios::binary);

    if(!is) throw std::runtime_error(filename + ": " + std::strerror(errno));

    return {std::istreambuf_iterator<char>(is),
            std::istreambuf_iterator<char>{}};
}

int main() {
    // Your current code up until you open the database.
    // ..
    Status s = DB::Open(options,DBPATH,&db);
    assert(status.ok());

    char key = '1';
    auto buffer = get_file_content("target.jpg");

    Slice key_in(&key, sizeof key);
    Slice slice(buffer.data(), buffer.size());
    status = db->Put(woptions, key_in, slice);

    std::cout << status.ToString() << '\n';

    delete db; // the only cleanup needed

    std::cout << "Done\n";
}

Upvotes: 0

Related Questions