diff --git a/0001-Allow-leveldbjni-build.patch b/0001-Allow-leveldbjni-build.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e32bfbe5a597e421d7a7308a2bce9834b3d0fb7 --- /dev/null +++ b/0001-Allow-leveldbjni-build.patch @@ -0,0 +1,49 @@ +From 77961bc308c89cda06a3fb1dc2cfa9c9ced2ba48 Mon Sep 17 00:00:00 2001 +From: Hiram Chirino +Date: Fri, 5 Jul 2013 18:32:28 +0400 +Subject: [PATCH 1/4] Allow leveldbjni build + +--- + build_detect_platform | 5 +++-- + include/leveldb/slice.h | 1 - + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/build_detect_platform b/build_detect_platform +index d2a20ce5b6277594ec256004121195a22b049263..fb32ae9eab6f39d62e0478d87a73579c414e9f5a 100755 +--- a/build_detect_platform ++++ b/build_detect_platform +@@ -245,12 +245,13 @@ PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS" + echo "CC=$CC" >> $OUTPUT + echo "CXX=$CXX" >> $OUTPUT + echo "PLATFORM=$PLATFORM" >> $OUTPUT + echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT + echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT +-echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT +-echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT ++echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS $PLATFORM_SHARED_CFLAGS" >> $OUTPUT ++echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS $PLATFORM_SHARED_CFLAGS" >> $OUTPUT ++echo "PLATFORM_SHARED_CFLAGS=" >> $OUTPUT + echo "PLATFORM_SSEFLAGS=$PLATFORM_SSEFLAGS" >> $OUTPUT + echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT + echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT + echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT + echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT +diff --git a/include/leveldb/slice.h b/include/leveldb/slice.h +index bc367986f7e8e26fdf22afc02283d4dd13970158..6f2289aaad763b83d88ccffd259540c4827b1a6a 100644 +--- a/include/leveldb/slice.h ++++ b/include/leveldb/slice.h +@@ -75,11 +75,10 @@ class Slice { + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && + (memcmp(data_, x.data_, x.size_) == 0)); + } + +- private: + const char* data_; + size_t size_; + + // Intentionally copyable + }; +-- +2.14.2 + diff --git a/0002-Added-a-DB-SuspendCompations-and-DB-ResumeCompaction.patch b/0002-Added-a-DB-SuspendCompations-and-DB-ResumeCompaction.patch new file mode 100644 index 0000000000000000000000000000000000000000..eba41c1e4812ba83eaf87709da5c2e7c3c5209de --- /dev/null +++ b/0002-Added-a-DB-SuspendCompations-and-DB-ResumeCompaction.patch @@ -0,0 +1,154 @@ +From 9f7a39eb2fc0bf4e7c4df64dca5e3ed01cbde2c1 Mon Sep 17 00:00:00 2001 +From: Hiram Chirino +Date: Tue, 30 Oct 2012 16:56:52 -0400 +Subject: [PATCH 2/4] Added a DB:SuspendCompations() and DB:ResumeCompactions() + methods. Fixes issue #184 + +https://code.google.com/p/leveldb/issues/detail?id=184 +--- + db/db_impl.cc | 36 ++++++++++++++++++++++++++++++++++++ + db/db_impl.h | 9 +++++++++ + db/db_test.cc | 4 ++++ + include/leveldb/db.h | 6 ++++++ + 4 files changed, 55 insertions(+) + +diff --git a/db/db_impl.cc b/db/db_impl.cc +index f43ad7679436b312959e5e0487c9313694d83ecc..60c483fab11177fb2d37726f3b2a94720e4dd1ff 100644 +--- a/db/db_impl.cc ++++ b/db/db_impl.cc +@@ -123,10 +123,13 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), + dbname_(dbname), + db_lock_(NULL), + shutting_down_(NULL), ++ suspend_cv(&suspend_mutex), ++ suspend_count(0), ++ suspended(false), + bg_cv_(&mutex_), + mem_(NULL), + imm_(NULL), + logfile_(NULL), + logfile_number_(0), +@@ -1469,10 +1472,43 @@ void DBImpl::GetApproximateSizes( + MutexLock l(&mutex_); + v->Unref(); + } + } + ++void DBImpl::SuspendCompactions() { ++ MutexLock l(& suspend_mutex); ++ env_->Schedule(&SuspendWork, this); ++ suspend_count++; ++ while( !suspended ) { ++ suspend_cv.Wait(); ++ } ++} ++void DBImpl::SuspendWork(void* db) { ++ reinterpret_cast(db)->SuspendCallback(); ++} ++void DBImpl::SuspendCallback() { ++ MutexLock l(&suspend_mutex); ++ Log(options_.info_log, "Compactions suspended"); ++ suspended = true; ++ suspend_cv.SignalAll(); ++ while( suspend_count > 0 ) { ++ suspend_cv.Wait(); ++ } ++ suspended = false; ++ suspend_cv.SignalAll(); ++ Log(options_.info_log, "Compactions resumed"); ++} ++void DBImpl::ResumeCompactions() { ++ MutexLock l(&suspend_mutex); ++ suspend_count--; ++ suspend_cv.SignalAll(); ++ while( suspended ) { ++ suspend_cv.Wait(); ++ } ++} ++ ++ + // Default implementations of convenience methods that subclasses of DB + // can call if they wish + Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); +diff --git a/db/db_impl.h b/db/db_impl.h +index 8ff323e72879967a9ff27876155a21ffb2330d3d..78f910356318cfdd3bb4ee029a50d8a76161037f 100644 +--- a/db/db_impl.h ++++ b/db/db_impl.h +@@ -39,10 +39,12 @@ class DBImpl : public DB { + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); ++ virtual void SuspendCompactions(); ++ virtual void ResumeCompactions(); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); +@@ -131,10 +133,17 @@ class DBImpl : public DB { + TableCache* table_cache_; + + // Lock over the persistent DB state. Non-NULL iff successfully acquired. + FileLock* db_lock_; + ++ port::Mutex suspend_mutex; ++ port::CondVar suspend_cv; ++ int suspend_count; ++ bool suspended; ++ static void SuspendWork(void* db); ++ void SuspendCallback(); ++ + // State below is protected by mutex_ + port::Mutex mutex_; + port::AtomicPointer shutting_down_; + port::CondVar bg_cv_; // Signalled when background work finishes + MemTable* mem_; +diff --git a/db/db_test.cc b/db/db_test.cc +index a0b08bc19c6510322dc65a94e135fa17ee922659..641fbabeeb6ed6e2537f024597c984cd4f3b846b 100644 +--- a/db/db_test.cc ++++ b/db/db_test.cc +@@ -1864,10 +1864,14 @@ class ModelDB: public DB { + KVMap map_; + }; + + explicit ModelDB(const Options& options): options_(options) { } + ~ModelDB() { } ++ ++ virtual void SuspendCompactions() {} ++ virtual void ResumeCompactions() {} ++ + virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { + return DB::Put(o, k, v); + } + virtual Status Delete(const WriteOptions& o, const Slice& key) { + return DB::Delete(o, key); +diff --git a/include/leveldb/db.h b/include/leveldb/db.h +index bfab10a0b725be9ed218783ee8fc98110fa77988..a69704d297c3feb1f60dc2856d6f9709a8879a86 100644 +--- a/include/leveldb/db.h ++++ b/include/leveldb/db.h +@@ -140,10 +140,16 @@ class DB { + // end==NULL is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(NULL, NULL); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; + ++ // Suspends the background compaction thread. This methods ++ // returns once suspended. ++ virtual void SuspendCompactions() = 0; ++ // Resumes a suspended background compation thread. ++ virtual void ResumeCompactions() = 0; ++ + private: + // No copying allowed + DB(const DB&); + void operator=(const DB&); + }; +-- +2.14.2 + diff --git a/0003-allow-Get-calls-to-avoid-copies-into-std-string.patch b/0003-allow-Get-calls-to-avoid-copies-into-std-string.patch new file mode 100644 index 0000000000000000000000000000000000000000..93b5099f640e99658fc45a2930109575efe3cc04 --- /dev/null +++ b/0003-allow-Get-calls-to-avoid-copies-into-std-string.patch @@ -0,0 +1,232 @@ +From d2505cb2966d016b4b28214eb81f4a38860549ea Mon Sep 17 00:00:00 2001 +From: Steve Vinoski +Date: Thu, 20 Dec 2012 16:14:11 -0500 +Subject: [PATCH 3/4] allow Get() calls to avoid copies into std::string + +Add a new abstract base class leveldb::Value that applications can easily +derive from to supply their own memory management for values retrieved via +Get(). Add an internal class derived from Value that provides std::string +management to preserve backward compatibility. Overload DBImpl::Get() to +accept a Value*, and to preserve backward compatibility also keep the +original version taking a std::string*. +--- + db/db_impl.cc | 23 +++++++++++++++++++++++ + db/db_impl.h | 3 +++ + db/db_test.cc | 5 +++++ + db/memtable.cc | 2 +- + db/memtable.h | 2 +- + db/version_set.cc | 4 ++-- + db/version_set.h | 2 +- + include/leveldb/db.h | 13 +++++++++++++ + 8 files changed, 49 insertions(+), 5 deletions(-) + +diff --git a/db/db_impl.cc b/db/db_impl.cc +index 60c483fab11177fb2d37726f3b2a94720e4dd1ff..50ee5ef22d3416b7bf256b06659e4e705278515d 100644 +--- a/db/db_impl.cc ++++ b/db/db_impl.cc +@@ -79,10 +79,26 @@ struct DBImpl::CompactionState { + builder(NULL), + total_bytes(0) { + } + }; + ++Value::~Value() {} ++ ++class StringValue : public Value { ++ public: ++ explicit StringValue(std::string& val) : value_(val) {} ++ ~StringValue() {} ++ ++ StringValue& assign(const char* data, size_t size) { ++ value_.assign(data, size); ++ return *this; ++ } ++ ++ private: ++ std::string& value_; ++}; ++ + // Fix user-supplied options to be reasonable + template + static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +@@ -1110,10 +1126,17 @@ int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + } + + Status DBImpl::Get(const ReadOptions& options, + const Slice& key, + std::string* value) { ++ StringValue stringvalue(*value); ++ return DBImpl::Get(options, key, &stringvalue); ++} ++ ++Status DBImpl::Get(const ReadOptions& options, ++ const Slice& key, ++ Value* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != NULL) { + snapshot = reinterpret_cast(options.snapshot)->number_; +diff --git a/db/db_impl.h b/db/db_impl.h +index 78f910356318cfdd3bb4ee029a50d8a76161037f..14c44d8751bc838ffd18e44f7398e1f728375b48 100644 +--- a/db/db_impl.h ++++ b/db/db_impl.h +@@ -33,10 +33,13 @@ class DBImpl : public DB { + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, + const Slice& key, + std::string* value); ++ virtual Status Get(const ReadOptions& options, ++ const Slice& key, ++ Value* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); +diff --git a/db/db_test.cc b/db/db_test.cc +index 641fbabeeb6ed6e2537f024597c984cd4f3b846b..a1769d24aea84863716cd242de4457fb75dd0413 100644 +--- a/db/db_test.cc ++++ b/db/db_test.cc +@@ -1879,10 +1879,15 @@ class ModelDB: public DB { + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) { + assert(false); // Not implemented + return Status::NotFound(key); + } ++ virtual Status Get(const ReadOptions& options, ++ const Slice& key, Value* value) { ++ assert(false); // Not implemented ++ return Status::NotFound(key); ++ } + virtual Iterator* NewIterator(const ReadOptions& options) { + if (options.snapshot == NULL) { + KVMap* saved = new KVMap; + *saved = map_; + return new ModelIter(saved, true); +diff --git a/db/memtable.cc b/db/memtable.cc +index bfec0a7e7a1dc210b44dd527b9547e33e829d9bb..82a875fc3abc6ca833c5a396f695652ff8a3dd52 100644 +--- a/db/memtable.cc ++++ b/db/memtable.cc +@@ -103,11 +103,11 @@ void MemTable::Add(SequenceNumber s, ValueType type, + memcpy(p, value.data(), val_size); + assert((p + val_size) - buf == encoded_len); + table_.Insert(buf); + } + +-bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { ++bool MemTable::Get(const LookupKey& key, Value* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: +diff --git a/db/memtable.h b/db/memtable.h +index 9f41567cde23dfd645b19d290c6e4a4256804900..6c3f56699798c936531f153a1b45707668935b80 100644 +--- a/db/memtable.h ++++ b/db/memtable.h +@@ -56,11 +56,11 @@ class MemTable { + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. +- bool Get(const LookupKey& key, std::string* value, Status* s); ++ bool Get(const LookupKey& key, Value* value, Status* s); + + private: + ~MemTable(); // Private since only Unref() should be used to delete it + + struct KeyComparator { +diff --git a/db/version_set.cc b/db/version_set.cc +index b1256f90e1c2bc6f9f6f449029bed9266bbb55b9..f0a523930d3382983fddfe27ee700574ddd06b3d 100644 +--- a/db/version_set.cc ++++ b/db/version_set.cc +@@ -260,11 +260,11 @@ enum SaverState { + }; + struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; +- std::string* value; ++ Value* value; + }; + } + static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; +@@ -329,11 +329,11 @@ void Version::ForEachOverlapping(Slice user_key, Slice internal_key, + } + } + + Status Version::Get(const ReadOptions& options, + const LookupKey& k, +- std::string* value, ++ Value* value, + GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; +diff --git a/db/version_set.h b/db/version_set.h +index c4e7ac360b87d842ee9dbc0a2bf80f122a65dad7..2d31542cff63b9058c991e3bd0b67f41102edbed 100644 +--- a/db/version_set.h ++++ b/db/version_set.h +@@ -68,11 +68,11 @@ class Version { + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; +- Status Get(const ReadOptions&, const LookupKey& key, std::string* val, ++ Status Get(const ReadOptions&, const LookupKey& key, Value* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held +diff --git a/include/leveldb/db.h b/include/leveldb/db.h +index a69704d297c3feb1f60dc2856d6f9709a8879a86..12f788ebf76341102832f45132388ef432db7e25 100644 +--- a/include/leveldb/db.h ++++ b/include/leveldb/db.h +@@ -36,10 +36,21 @@ struct Range { + + Range() { } + Range(const Slice& s, const Slice& l) : start(s), limit(l) { } + }; + ++// Abstract holder for a DB value. ++// This allows callers to manage their own value buffers and have ++// DB values copied directly into those buffers. ++class Value { ++ public: ++ virtual Value& assign(const char* data, size_t size) = 0; ++ ++ protected: ++ virtual ~Value(); ++}; ++ + // A DB is a persistent ordered map from keys to values. + // A DB is safe for concurrent access from multiple threads without + // any external synchronization. + class DB { + public: +@@ -80,10 +91,12 @@ class DB { + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) = 0; ++ virtual Status Get(const ReadOptions& options, ++ const Slice& key, Value* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // +-- +2.14.2 + diff --git a/0004-bloom_test-failure-on-big-endian-archs.patch b/0004-bloom_test-failure-on-big-endian-archs.patch new file mode 100644 index 0000000000000000000000000000000000000000..872a3e2b5c5ddb459a883d72dea198ceb767cf83 --- /dev/null +++ b/0004-bloom_test-failure-on-big-endian-archs.patch @@ -0,0 +1,38 @@ +From 9992080e51c3deff0b82ce838b64ef6b68bd81f0 Mon Sep 17 00:00:00 2001 +From: Yehuda Sadeh +Date: Mon, 2 Jul 2012 14:29:06 -0700 +Subject: [PATCH 4/4] bloom_test failure on big endian archs + +When running bloom_test on big endian machines it fails due to unacceptable +false positive rate. I've looked into the issue and it seems that the +reason for that is that it passes a different input than when it runs on +little endian. When transforming the input to be little endian it behaves +as expected. +This issue holds up inclusion of ceph to debian due to ceph's use of +leveldb. The fix can be to bump up the acceptable false positives. + +https://groups.google.com/d/topic/leveldb/SbVPvl4j4vU/discussion +--- + util/bloom_test.cc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/bloom_test.cc b/util/bloom_test.cc +index 1b87a2be3f540c673ee1749b0b855d396251f5aa..e464548c339d8a8a3f9a620ddcd73710c3825c2f 100644 +--- a/util/bloom_test.cc ++++ b/util/bloom_test.cc +@@ -140,11 +140,11 @@ TEST(BloomTest, VaryingLengths) { + double rate = FalsePositiveRate(); + if (kVerbose >= 1) { + fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate*100.0, length, static_cast(FilterSize())); + } +- ASSERT_LE(rate, 0.02); // Must not be over 2% ++ ASSERT_LE(rate, 0.03); // Must not be over 2% + if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often + else good_filters++; + } + if (kVerbose >= 1) { + fprintf(stderr, "Filters: %d good, %d mediocre\n", +-- +2.14.2 + diff --git a/leveldb-1.20.tar.gz b/leveldb-1.20.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3a82c0038e10a74dde9b1976b59c8c5e9bb1e677 Binary files /dev/null and b/leveldb-1.20.tar.gz differ diff --git a/leveldb.spec b/leveldb.spec new file mode 100644 index 0000000000000000000000000000000000000000..dc1bb47c81032e6f9e9a46831a41803b6dc6c8c0 --- /dev/null +++ b/leveldb.spec @@ -0,0 +1,75 @@ +Name: leveldb +Version: 1.20 +Release: 4 +Summary: A key/value database library +License: BSD +URL: https://github.com/google/leveldb +Source0: https://github.com/google/leveldb/archive/v%{version}/%{name}-%{version}.tar.gz + +Patch0001: 0001-Allow-leveldbjni-build.patch +Patch0002: 0002-Added-a-DB-SuspendCompations-and-DB-ResumeCompaction.patch +Patch0003: 0003-allow-Get-calls-to-avoid-copies-into-std-string.patch +Patch0004: 0004-bloom_test-failure-on-big-endian-archs.patch + +BuildRequires: make gcc-c++ snappy-devel + +%description +LevelDB is a fast key-value storage library written at Google that provides an +ordered mapping from string keys to string values. + +%package devel +Summary: Development files for leveldb +Requires: %{name}%{?_isa} = %{?epoch:%{epoch}:}%{version}-%{release} + +%description devel +Development files for leveldb. + +%prep +%autosetup -p1 +cat > leveldb.pc << EOF +prefix=%{_prefix} +exec_prefix=${prefix} +libdir=%{_libdir} +includedir=%{_includedir} + +Name: leveldb +Description: A key/value database library +Version: %{version} +Libs: -lleveldb +EOF + +%global configure() {export OPT="-DNDEBUG" export CFLAGS="%{optflags}" export CXXFLAGS="%{optflags}" export LDFLAGS="%{__global_ldflags}" } + +%build +%configure +make -O -j1 + +%install +install -d %{buildroot}{%{_libdir}/pkgconfig,%{_includedir}} +cp -a out-shared/libleveldb.so* %{buildroot}%{_libdir}/ +install -p leveldb.pc %{buildroot}%{_libdir}/pkgconfig/leveldb.pc +cp -a include/leveldb/ %{buildroot}%{_includedir}/ + +%check +%configure +make -j1 check + +%post +/sbin/ldconfig +%postun +/sbin/ldconfig + +%files +%license LICENSE +%doc AUTHORS README.md NEWS +%{_libdir}/lib%{name}.so.* + +%files devel +%doc doc/ CONTRIBUTING.md TODO +%{_includedir}/leveldb/ +%{_libdir}/libleveldb.so +%{_libdir}/pkgconfig/leveldb.pc + +%changelog +* Fri Dec 20 2019 wangyiru - 1.20-4 +- Package init