【问题标题】:LevelDB C iteratorLevelDB C 迭代器
【发布时间】:2016-03-28 12:34:07
【问题描述】:

我需要用 c 语言遍历 leveldb 数据库 - https://github.com/google/leveldb/blob/master/include/leveldb/c.h。除了迭代,一切正常。结果带有一些二进制噪声数据:

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

我用$&*#等符号显示二进制输出,stackoverflow不允许在这里放二进制输出。

代码:

#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);
}

如何在 C 中正确遍历 LevelDB?

【问题讨论】:

    标签: c leveldb


    【解决方案1】:

    leveldb_iter_keyleveldb_iter_value 返回的值似乎不是正确的以 NULL 结尾的字符串。

    所以,使用肮脏的解决方案

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

    而不是

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

    但是,IMO 最好根据它们的长度复制这些值,然后使用它们。

    正如您在https://github.com/google/leveldb/blob/master/db/c.cc#L197 中看到的,leveldb_get 创建适当长度的切片(L205 上的Slice(key, keylen))并返回密钥的副本(L208 上的CopyString)。

    补充:

    我已经使用 valgrind 检查了您的代码,并且存在一些带有选项的内存泄漏。您应该手动释放它们(例如,leveldb_writeoptions_destroy for woptions)。 leveldb_get 结果 (read) 也应该被释放。

    示例代码:

    // 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);
    

    【讨论】:

    • github.com/google/leveldb/blob/master/db/c.cc#L197 - 它的 C++,但我需要 C 版本
    • @SebastianRockefeller LevelDB 是用 C++ 编写的,但您可以将它与 C 一起使用。
    • @SebastianRockefeller 在 C 中使用 strncpymemcpy 然后手动 NULL 终止结果;
    • 能写个例子吗?
    • @SebastianRockefeller 我已经发布了一些示例代码。
    【解决方案2】:

    LevelDB 不使用 C(++) 字符串作为键和值,它使用可能包含 NUL 且不是 NUL 终止的字节数组。这记录在这里:1

    使用任何面向字符串的 C 函数来操作这些数组都是错误的。您可以使用printf 来安全地显示返回值。

    【讨论】:

      猜你喜欢
      • 2018-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多