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