LevelDB C iterator

主宰稳场 提交于 2019-12-11 01:19:44

问题


I need to iterate through the leveldb database in c language - https://github.com/google/leveldb/blob/master/include/leveldb/c.h. Everything works except iterating.The result goes with some binary noise data:

key: value1
key: value2
key#&^$&*# value
one1(*@(# value1
two2%*@( value2

With $&*#, etc. symbols I showed the binary output, stackoverflow does not allow to put here binary output.

The code:

#include <leveldb/c.h>
#include <stdio.h>

int main() {
    leveldb_t *db;
    leveldb_options_t *options;
    leveldb_readoptions_t *roptions;
    leveldb_writeoptions_t *woptions;
    char *err = NULL;
    char *read;
    size_t read_len;

    /******************************************/
    /* OPEN */

    options = leveldb_options_create();
    leveldb_options_set_create_if_missing(options, 1);
    db = leveldb_open(options, "testdb", &err);

    if (err != NULL) {
      fprintf(stderr, "Open fail.\n");
      return(1);
    }

    /* reset error var */
    leveldb_free(err); err = NULL;

    /******************************************/
    /* WRITE */

    woptions = leveldb_writeoptions_create();
    leveldb_put(db, woptions, "one", 3, "value1", 6, &err);

    if (err != NULL) {
      fprintf(stderr, "Write fail.\n");
      return(1);
    }

    leveldb_free(err); err = NULL;

    /******************************************/
    /* WRITE 2 */

    woptions = leveldb_writeoptions_create();
    leveldb_put(db, woptions, "two", 3, "value2", 6, &err);

    if (err != NULL) {
      fprintf(stderr, "Write fail.\n");
      return(1);
    }

    leveldb_free(err); err = NULL;

    /******************************************/
    /* READ */

    roptions = leveldb_readoptions_create();
    read = leveldb_get(db, roptions, "one", 3, &read_len, &err);

    if (err != NULL) {
      fprintf(stderr, "Read fail.\n");
      return(1);
    }

    printf("key: %s\n", read);

    leveldb_free(err); err = NULL;

    /******************************************/
    /* READ 2 */

    roptions = leveldb_readoptions_create();
    read = leveldb_get(db, roptions, "two", 3, &read_len, &err);

    if (err != NULL) {
      fprintf(stderr, "Read fail.\n");
      return(1);
    }

    printf("key: %s\n", read);

    leveldb_free(err); err = NULL;

    /******************************************/
    /* ITERATE */

    roptions = leveldb_readoptions_create();
    leveldb_iterator_t *iter = leveldb_create_iterator(db, roptions);

    for (leveldb_iter_seek_to_first(iter); leveldb_iter_valid(iter); leveldb_iter_next(iter))
    {
        size_t key_len, value_len;
        const char *key_ptr = leveldb_iter_key(iter, &key_len);
        const char *value_ptr = leveldb_iter_value(iter, &value_len);

        /* Prints some binary noise with the data */
        printf("%s %s\n", key_ptr, value_ptr);
    }
    leveldb_iter_destroy(iter);
    leveldb_free(err); err = NULL;

    /******************************************/
    /* CLOSE */

    leveldb_close(db);

    return(0);
}

How to correctly iterate through LevelDB in C?


回答1:


It seems that values returned by leveldb_iter_key and leveldb_iter_value are not correct NULL-terminated strings.

So, the dirty solution would be use

printf("%.*s %.*s\n", (int) key_len, key_ptr, (int) value_len, value_ptr);

instead of

printf("%s %s\n", key_ptr, value_ptr);

However, IMO it's better to copy those values according to their length and then use them.

As you can see in https://github.com/google/leveldb/blob/master/db/c.cc#L197 leveldb_get creates slice of appropriate length (Slice(key, keylen) on L205) and returns copy of the key (CopyString on L208).

Additional:

I've checked your code with valgrind and there are some memory leaks with options. You should manually free them (e.g. leveldb_writeoptions_destroy for woptions). leveldb_get results (read) should also be freed.

Example code:

// allocate new strings
char * key = (char *) malloc(key_len + 1);
char * value = (char *) malloc(value_len + 1);

// copy string content and ensure that string is null-terminated
memcpy(key, key_ptr, key_len);
key[key_len] = 0;
memcpy(value, value_ptr, value_len);
value[value_len] = 0;

// print
printf("%s %s\n", key, value);

// free
free(key);
free(value);



回答2:


LevelDB does not use C(++) strings for keys and values, it uses arrays of bytes which may contain NULs and are not NUL-terminated. This is documented here: 1.

It would be wrong to use any C string-oriented function to manipulate these arrays. You can not use printf to safely display the returned values.



来源:https://stackoverflow.com/questions/36262408/leveldb-c-iterator

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!