表現:通過JNI打開RocksDB報錯:snappy壓縮庫沒有被鏈接:
org.rocksdb.RocksDBException: Compression type Snappy is not linked with the binary.
at org.rocksdb.RocksDB.open(Native Method) ~[rocksdbjni-6.6.0-fix-osx.jar:?]
at org.rocksdb.RocksDB.open(RocksDB.java:290) ~[rocksdbjni-6.6.0-fix-osx.jar:?]
at com.baidu.hugegraph.backend.store.rocksdb.RocksDBStdSessions.<init>(RocksDBStdSessions.java:130) ~[classes/:?]
at com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore.openSessionPool(RocksDBStore.java:299) ~[classes/:?]
at com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore.open(RocksDBStore.java:237) ~[classes/:?]
at com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore.open(RocksDBStore.java:228) ~[classes/:?]
從官網下載的release包是沒有問題的,由於這個是我Mac本地編譯包,所以報錯應該是本地環境導致的。看到這個錯誤信息直覺是想可能沒有安裝libsnappy
導致的,於是brew install snappy
安裝了一下,再次啓動RocksDB發現還是同樣的錯誤,沒想到這小問題還很頑固,於是決定分析下究竟什麼原因。
1、找到了報錯的代碼行,
Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options) {
if (!cf_options.compression_per_level.empty()) {
for (size_t level = 0; level < cf_options.compression_per_level.size();
++level) {
if (!CompressionTypeSupported(cf_options.compression_per_level[level])) {
return Status::InvalidArgument(
"Compression type " +
CompressionTypeToString(cf_options.compression_per_level[level]) +
" is not linked with the binary."); // <======= 這裏報錯
}
}
} else {
if (!CompressionTypeSupported(cf_options.compression)) {
return Status::InvalidArgument(
"Compression type " +
CompressionTypeToString(cf_options.compression) +
" is not linked with the binary.");
}
}
...
}
事實上,在打開RockSD.open()的時候,會調用
ValidateOptions()
方法檢查ColumnFamilyOptions配置項是否合法:Status ColumnFamilyData::ValidateOptions( const DBOptions& db_options, const ColumnFamilyOptions& cf_options) { Status s; s = CheckCompressionSupported(cf_options); if (s.ok() && db_options.allow_concurrent_memtable_write) { s = CheckConcurrentWritesSupported(cf_options); } if (s.ok()) { s = CheckCFPathsSupported(db_options, cf_options); } if (!s.ok()) { return s; } ... }
2、從報錯代碼行上面的if
語句看出當調用CompressionTypeSupported()
方法返回false
時會報這個錯。
看看CompressionTypeSupported()
方法裏面是怎麼實現的:
inline bool CompressionTypeSupported(CompressionType compression_type) {
switch (compression_type) {
case kNoCompression:
return true;
case kSnappyCompression:
return Snappy_Supported();
case kZlibCompression:
return Zlib_Supported();
...
}
inline bool Snappy_Supported() {
#ifdef SNAPPY
return true;
#else
return false;
#endif
}
爲何CompressionTypeSupported()
方法返回false
?從上述代碼看出該方法根據壓縮類型switch-case調用了各自實現,snappy
壓縮時調用Snappy_Supported()
方法,其邏輯很簡單:在編譯時如果定義了SNAPPY
則表示支持。所以這個錯誤與運行時無關,預編譯的時候就決定了是否支持snappy
壓縮。
3、那問題來了,爲什麼我本地編譯的時候沒有定義SNAPPY
呢?猜測應該是自動根據本地編譯環境檢測是否有相關依賴庫,或者提供開關選項由用戶指定是否開啓。
查看爲何沒有啓用SNAPPY
:在Makefile中,會調用build_tools/build_detect_platform
腳本生成make_config.mk
編譯配置文件:
# detect what platform we're building on
dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; export PORTABLE="$(PORTABLE)"; "$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk"))
# this file is generated by the previous line to set build flags and sources
include make_config.mk
查看build_detect_platform腳本,找到了SNAPPY
檢測代碼:如果snappy已安裝則輸出-DSNAPPY
配置項:
if ! test $ROCKSDB_DISABLE_SNAPPY; then
# Test whether Snappy library is installed
# http://code.google.com/p/snappy/
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
#include <snappy.h>
int main() {}
EOF
if [ "$?" = 0 ]; then
COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY"
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lsnappy"
JAVA_LDFLAGS="$JAVA_LDFLAGS -lsnappy"
fi
fi
4、最終解決方法:本地安裝snappy庫之後,重新編譯RocksDB即可,驗證OK。
brew install snappy
make rocksdbjava
5、其它需要注意的地方:
如何禁用壓縮庫編譯:
看起來可以通過兩個開關顯示禁用:ROCKSDB_DISABLE_SNAPPY或ROCKSDB_JAVA_NO_COMPRESSION,待驗證。
強制編譯問題:
如果沒有安裝snappy庫強制指定要編譯的話
make OPT=-DSNAPPY rocksdbjava
,是無法編譯通過的,會報錯:"./util/compression.h:31:10: fatal error: ‘snappy.h’ file not found" 或者 “ld: library not found for -lsnappy”。
動態庫找不到問題:
如果編譯過了後,拷到本地無snappy動態庫的機器執行會報錯:“java.lang.NoClassDefFoundError: Could not initialize class org.rocksdb.Options”。
需要以靜態庫方式鏈接依賴(本身還是動態庫):
make rocksdbjavastatic
或make rocksdbjavastaticrelease
。
依賴包括:JAVA_COMPRESSIONS = libz.a libbz2.a libsnappy.a liblz4.a libzstd.a。
RocksDB中編譯snappy
指令詳見libsnappy.a。
Windows平臺注意:
在Windows平臺上實際上是提供開關選項,在
CMakeLists
中有一個WITH_SNAPPY
開關控制是否編譯snappy:if(WITH_SNAPPY) find_package(snappy REQUIRED) add_definitions(-DSNAPPY) list(APPEND THIRDPARTY_LIBS snappy::snappy) endif()
option(WITH_JEMALLOC "build with JeMalloc" OFF) option(WITH_SNAPPY "build with SNAPPY" OFF) option(WITH_LZ4 "build with lz4" OFF) option(WITH_ZLIB "build with zlib" OFF) option(WITH_ZSTD "build with zstd" OFF)
壓縮相關的幾個開關默認都是關閉的,如果需要打開請使用:
cmake -DWITH_SNAPPY=1