1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "LevelDBDatabase.h" 28 29#if USE(LEVELDB) 30 31#include "LevelDBComparator.h" 32#include "LevelDBIterator.h" 33#include "LevelDBSlice.h" 34#include "LevelDBWriteBatch.h" 35#include "Logging.h" 36#include "NotImplemented.h" 37#include <helpers/memenv/memenv.h> 38#include <leveldb/comparator.h> 39#include <leveldb/db.h> 40#include <leveldb/env.h> 41#include <leveldb/slice.h> 42#include <string> 43#include <wtf/text/CString.h> 44#include <wtf/text/WTFString.h> 45 46namespace leveldb { 47 48static Env* IDBEnv() 49{ 50 return leveldb::Env::Default(); 51} 52 53} 54 55namespace WebCore { 56 57static leveldb::Slice makeSlice(const Vector<char>& value) 58{ 59 return leveldb::Slice(value.data(), value.size()); 60} 61 62static leveldb::Slice makeSlice(const LevelDBSlice& s) 63{ 64 return leveldb::Slice(s.begin(), s.end() - s.begin()); 65} 66 67static LevelDBSlice makeLevelDBSlice(const leveldb::Slice& s) 68{ 69 return LevelDBSlice(s.data(), s.data() + s.size()); 70} 71 72class ComparatorAdapter : public leveldb::Comparator { 73public: 74 ComparatorAdapter(const LevelDBComparator* comparator) 75 : m_comparator(comparator) 76 { 77 } 78 79 virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const 80 { 81 return m_comparator->compare(makeLevelDBSlice(a), makeLevelDBSlice(b)); 82 } 83 84 virtual const char* Name() const { return m_comparator->name(); } 85 86 // FIXME: Support the methods below in the future. 87 virtual void FindShortestSeparator(std::string* /* start */, const leveldb::Slice& /* limit */) const { } 88 virtual void FindShortSuccessor(std::string* /* key */) const { } 89 90private: 91 const LevelDBComparator* m_comparator; 92}; 93 94LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) 95 : m_db(db->m_db.get()) 96 , m_snapshot(m_db->GetSnapshot()) 97{ 98} 99 100LevelDBSnapshot::~LevelDBSnapshot() 101{ 102 m_db->ReleaseSnapshot(m_snapshot); 103} 104 105LevelDBDatabase::LevelDBDatabase() 106{ 107} 108 109LevelDBDatabase::~LevelDBDatabase() 110{ 111 // m_db's destructor uses m_comparatorAdapter; order of deletion is important. 112 m_db = nullptr; 113 m_comparatorAdapter = nullptr; 114 m_env = nullptr; 115} 116 117static leveldb::Status openDB(leveldb::Comparator* comparator, leveldb::Env* env, const String& path, leveldb::DB** db) 118{ 119 leveldb::Options options; 120 options.comparator = comparator; 121 options.create_if_missing = true; 122 options.paranoid_checks = true; 123 // 20 max_open_files is the minimum LevelDB allows. 124 options.max_open_files = 20; 125 options.env = env; 126 127 return leveldb::DB::Open(options, path.utf8().data(), db); 128} 129 130bool LevelDBDatabase::destroy(const String& fileName) 131{ 132 leveldb::Options options; 133 options.env = leveldb::IDBEnv(); 134 const leveldb::Status s = leveldb::DestroyDB(fileName.utf8().data(), options); 135 return s.ok(); 136} 137 138std::unique_ptr<LevelDBDatabase> LevelDBDatabase::open(const String& fileName, const LevelDBComparator* comparator) 139{ 140 auto comparatorAdapter = std::make_unique<ComparatorAdapter>(comparator); 141 142 leveldb::DB* db; 143 const leveldb::Status s = openDB(comparatorAdapter.get(), leveldb::IDBEnv(), fileName, &db); 144 145 if (!s.ok()) { 146 LOG_ERROR("Failed to open LevelDB database from %s: %s", fileName.ascii().data(), s.ToString().c_str()); 147 return nullptr; 148 } 149 150 auto result = std::make_unique<LevelDBDatabase>(); 151 result->m_db = std::unique_ptr<leveldb::DB>(db); 152 result->m_comparatorAdapter = WTF::move(comparatorAdapter); 153 result->m_comparator = comparator; 154 155 return result; 156} 157 158std::unique_ptr<LevelDBDatabase> LevelDBDatabase::openInMemory(const LevelDBComparator* comparator) 159{ 160 auto comparatorAdapter = std::make_unique<ComparatorAdapter>(comparator); 161 std::unique_ptr<leveldb::Env> inMemoryEnv(leveldb::NewMemEnv(leveldb::IDBEnv())); 162 163 leveldb::DB* db; 164 const leveldb::Status s = openDB(comparatorAdapter.get(), inMemoryEnv.get(), String(), &db); 165 166 if (!s.ok()) { 167 LOG_ERROR("Failed to open in-memory LevelDB database: %s", s.ToString().c_str()); 168 return nullptr; 169 } 170 171 auto result = std::make_unique<LevelDBDatabase>(); 172 result->m_env = WTF::move(inMemoryEnv); 173 result->m_db = std::unique_ptr<leveldb::DB>(db); 174 result->m_comparatorAdapter = WTF::move(comparatorAdapter); 175 result->m_comparator = comparator; 176 177 return result; 178} 179 180bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value) 181{ 182 leveldb::WriteOptions writeOptions; 183 writeOptions.sync = true; 184 185 const leveldb::Status s = m_db->Put(writeOptions, makeSlice(key), makeSlice(value)); 186 if (s.ok()) 187 return true; 188 LOG_ERROR("LevelDB put failed: %s", s.ToString().c_str()); 189 return false; 190} 191 192bool LevelDBDatabase::remove(const LevelDBSlice& key) 193{ 194 leveldb::WriteOptions writeOptions; 195 writeOptions.sync = true; 196 197 const leveldb::Status s = m_db->Delete(writeOptions, makeSlice(key)); 198 if (s.ok()) 199 return true; 200 if (s.IsNotFound()) 201 return false; 202 LOG_ERROR("LevelDB remove failed: %s", s.ToString().c_str()); 203 return false; 204} 205 206bool LevelDBDatabase::safeGet(const LevelDBSlice& key, Vector<char>& value, bool& found, const LevelDBSnapshot* snapshot) 207{ 208 found = false; 209 std::string result; 210 leveldb::ReadOptions readOptions; 211 readOptions.verify_checksums = true; // FIXME: Disable this if the performance impact is too great. 212 readOptions.snapshot = snapshot ? snapshot->m_snapshot : 0; 213 214 const leveldb::Status s = m_db->Get(readOptions, makeSlice(key), &result); 215 if (s.ok()) { 216 found = true; 217 value.clear(); 218 value.append(result.c_str(), result.length()); 219 return true; 220 } 221 if (s.IsNotFound()) 222 return true; 223 LOG_ERROR("LevelDB get failed: %s", s.ToString().c_str()); 224 return false; 225} 226 227bool LevelDBDatabase::write(LevelDBWriteBatch& writeBatch) 228{ 229 leveldb::WriteOptions writeOptions; 230 writeOptions.sync = true; 231 232 const leveldb::Status s = m_db->Write(writeOptions, writeBatch.m_writeBatch.get()); 233 if (s.ok()) 234 return true; 235 LOG_ERROR("LevelDB write failed: %s", s.ToString().c_str()); 236 return false; 237} 238 239namespace { 240class IteratorImpl : public LevelDBIterator { 241public: 242 explicit IteratorImpl(std::unique_ptr<leveldb::Iterator>); 243 ~IteratorImpl() { }; 244 245 virtual bool isValid() const; 246 virtual void seekToLast(); 247 virtual void seek(const LevelDBSlice& target); 248 virtual void next(); 249 virtual void prev(); 250 virtual LevelDBSlice key() const; 251 virtual LevelDBSlice value() const; 252 253private: 254 void checkStatus(); 255 256 std::unique_ptr<leveldb::Iterator> m_iterator; 257}; 258} 259 260IteratorImpl::IteratorImpl(std::unique_ptr<leveldb::Iterator> it) 261 : m_iterator(WTF::move(it)) 262{ 263} 264 265void IteratorImpl::checkStatus() 266{ 267 const leveldb::Status s = m_iterator->status(); 268 if (!s.ok()) 269 LOG_ERROR("LevelDB iterator error: %s", s.ToString().c_str()); 270} 271 272bool IteratorImpl::isValid() const 273{ 274 return m_iterator->Valid(); 275} 276 277void IteratorImpl::seekToLast() 278{ 279 m_iterator->SeekToLast(); 280 checkStatus(); 281} 282 283void IteratorImpl::seek(const LevelDBSlice& target) 284{ 285 m_iterator->Seek(makeSlice(target)); 286 checkStatus(); 287} 288 289void IteratorImpl::next() 290{ 291 ASSERT(isValid()); 292 m_iterator->Next(); 293 checkStatus(); 294} 295 296void IteratorImpl::prev() 297{ 298 ASSERT(isValid()); 299 m_iterator->Prev(); 300 checkStatus(); 301} 302 303LevelDBSlice IteratorImpl::key() const 304{ 305 ASSERT(isValid()); 306 return makeLevelDBSlice(m_iterator->key()); 307} 308 309LevelDBSlice IteratorImpl::value() const 310{ 311 ASSERT(isValid()); 312 return makeLevelDBSlice(m_iterator->value()); 313} 314 315std::unique_ptr<LevelDBIterator> LevelDBDatabase::createIterator(const LevelDBSnapshot* snapshot) 316{ 317 leveldb::ReadOptions readOptions; 318 readOptions.verify_checksums = true; // FIXME: Disable this if the performance impact is too great. 319 readOptions.snapshot = snapshot ? snapshot->m_snapshot : 0; 320 std::unique_ptr<leveldb::Iterator> i(m_db->NewIterator(readOptions)); 321 if (!i) // FIXME: Double check if we actually need to check this. 322 return nullptr; 323 return std::make_unique<IteratorImpl>(WTF::move(i)); 324} 325 326const LevelDBComparator* LevelDBDatabase::comparator() const 327{ 328 return m_comparator; 329} 330 331} 332 333#endif 334