C++调用LevelDB PUT接口存储大文件时触发abort() has been called错误
LevelDB 调用Put触发abort问题排查
问题根因
你遇到的abort报错和LevelDB本身的配置、大小限制无关,完全是代码bug导致的非法内存访问触发的系统级中断,具体错误点如下:
- 内存越界:你用
calloc(1, size)申请了size字节的缓冲区,构造Slice时却传入了size + 1的长度,会导致LevelDB读取缓冲区外的非法内存 - 野指针访问:构造key对应的Slice时,你直接将char类型的
key值(ASCII码0x31)作为指针传入,相当于直接访问内存地址0x31,属于典型的野指针访问 - 参数传错:调用Put接口时你传入的是char类型的
key,而不是你构造的key_in,进一步放大了野指针问题 - 变量名不匹配:DB::Open的返回值赋值给了
s,后续assert却用了未赋值的status,导致Open阶段的错误没有被捕获 - 语法错误:
woptions.sync = true'末尾错写为单引号,key.clear()针对char类型调用不存在的方法,编译阶段就应该报错
修正方案
修正后的可运行代码如下:
FILE* file; WriteOptions woptions; woptions.sync = true; DB* db; Options options; options.create_if_missing = true; std::string DBPATH(DBName); const char key_char = '1'; Status s = DB::Open(options, DBPATH, &db); if (!s.ok()) { printf("open db failed: %s\n", s.ToString().c_str()); return -1; } errno_t err = fopen_s(&file, "target.jpg", "rb"); if (err != 0 || file == nullptr) { printf("open file failed\n"); delete db; return -1; } fseek(file, 0, SEEK_END); long long size = ftell(file); rewind(file); char* buffer = (char*)calloc(1, size); if (buffer == NULL) { printf("mem error\n"); fclose(file); delete db; return -1; } fread(buffer, size, 1, file); Slice value_slice(buffer, size); Slice key_slice(&key_char, sizeof(key_char)); s = db->Put(woptions, key_slice, value_slice); if (!s.ok()) { printf("put failed: %s\n", s.ToString().c_str()); } free(buffer); fclose(file); delete db;
LevelDB BLOB存储说明
LevelDB没有单独定义BLOB类型,因为它的key和value本身就原生支持任意长度的二进制字节流,不需要额外配置或特殊处理。默认单value最大支持2GB,只要你的二进制文件大小不超过该阈值就可以正常存储。你测试RocksDB和BerkeleyDB没有报错的原因是这两个数据库的参数校验、内存访问容错逻辑和LevelDB不同,掩盖了你代码的错误,并非LevelDB本身不支持大二进制存储。
内容的提问来源于stack exchange,提问作者Jeong Hwan Im
相关产品推荐
相关产品推荐

