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 ENABLE(LEVELDB)
30
31#include "LevelDBComparator.h"
32#include "LevelDBIterator.h"
33#include "LevelDBSlice.h"
34#include <leveldb/comparator.h>
35#include <leveldb/db.h>
36#include <leveldb/slice.h>
37#include <string>
38#include <wtf/PassOwnPtr.h>
39#include <wtf/text/CString.h>
40#include <wtf/text/WTFString.h>
41
42namespace WebCore {
43
44static leveldb::Slice makeSlice(const Vector<char>& value)
45{
46    return leveldb::Slice(value.data(), value.size());
47}
48
49static leveldb::Slice makeSlice(const LevelDBSlice& s)
50{
51    return leveldb::Slice(s.begin(), s.end() - s.begin());
52}
53
54static LevelDBSlice makeLevelDBSlice(const leveldb::Slice& s)
55{
56    return LevelDBSlice(s.data(), s.data() + s.size());
57}
58
59static Vector<char> makeVector(const std::string& s)
60{
61    Vector<char> res;
62    res.append(s.c_str(), s.length());
63    return res;
64}
65
66namespace {
67class ComparatorAdapter : public leveldb::Comparator {
68public:
69    ComparatorAdapter(const LevelDBComparator* comparator)
70        : m_comparator(comparator)
71    {
72    }
73
74    virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const
75    {
76        return m_comparator->compare(makeLevelDBSlice(a), makeLevelDBSlice(b));
77    }
78
79    virtual const char* Name() const { return m_comparator->name(); }
80
81    // FIXME: Support the methods below in the future.
82    virtual void FindShortestSeparator(std::string* start, const leveldb::Slice& limit) const { }
83    virtual void FindShortSuccessor(std::string* key) const { }
84
85private:
86    const LevelDBComparator* m_comparator;
87};
88}
89
90LevelDBDatabase::LevelDBDatabase()
91    : m_db(0)
92{
93}
94
95LevelDBDatabase::~LevelDBDatabase()
96{
97}
98
99LevelDBDatabase* LevelDBDatabase::open(const String& fileName, const LevelDBComparator* comparator)
100{
101    OwnPtr<ComparatorAdapter> comparatorAdapter(new ComparatorAdapter(comparator));
102
103    LevelDBDatabase* result = new LevelDBDatabase();
104
105    leveldb::Options options;
106    options.comparator = comparatorAdapter.get();
107    options.create_if_missing = true;
108    leveldb::DB* db;
109    leveldb::Status s = leveldb::DB::Open(options, fileName.utf8().data(), &db);
110
111    if (!s.ok()) {
112        delete result;
113        return 0;
114    }
115
116    result->m_db = WTF::adoptPtr(db);
117    result->m_comparatorAdapter = comparatorAdapter.release();
118
119    return result;
120}
121
122
123bool LevelDBDatabase::put(const LevelDBSlice& key, const Vector<char>& value)
124{
125    leveldb::WriteOptions writeOptions;
126    writeOptions.sync = false;
127
128    return m_db->Put(writeOptions, makeSlice(key), makeSlice(value)).ok();
129}
130
131bool LevelDBDatabase::remove(const LevelDBSlice& key)
132{
133    leveldb::WriteOptions writeOptions;
134    writeOptions.sync = false;
135
136    return m_db->Delete(writeOptions, makeSlice(key)).ok();
137}
138
139bool LevelDBDatabase::get(const LevelDBSlice& key, Vector<char>& value)
140{
141    std::string result;
142    if (!m_db->Get(leveldb::ReadOptions(), makeSlice(key), &result).ok())
143        return false;
144
145    value = makeVector(result);
146    return true;
147}
148
149LevelDBIterator* LevelDBDatabase::newIterator()
150{
151    leveldb::Iterator* i = m_db->NewIterator(leveldb::ReadOptions());
152    if (!i) // FIXME: Double check if we actually need to check this.
153        return 0;
154    return new LevelDBIterator(i);
155}
156
157} // namespace WebCore
158
159#endif // ENABLE(LEVELDB)
160