source: trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp @ 88019

Revision 88019, 46.3 KB checked in by hans@chromium.org, 3 years ago (diff)

2011-06-03 Hans Wennborg <hans@chromium.org>

Reviewed by Steve Block.

IndexedDB: Clean-up use of INT64_MAX in LevelDB back-end
https://bugs.webkit.org/show_bug.cgi?id=62009

This constant should only be needed inside IDBLevelDBCoding.cpp.

No new functionality, no new tests.

  • storage/IDBLevelDBBackingStore.cpp: (WebCore::getNewDatabaseId): (WebCore::IDBLevelDBBackingStore::getObjectStores): (WebCore::getNewObjectStoreId): (WebCore::IDBLevelDBBackingStore::deleteObjectStore): (WebCore::getNewIndexId):
  • storage/IDBLevelDBCoding.cpp: (WebCore::IDBLevelDBCoding::DatabaseFreeListKey::encodeMaxKey): (WebCore::IDBLevelDBCoding::ObjectStoreMetaDataKey::encodeMaxKey): (WebCore::IDBLevelDBCoding::IndexMetaDataKey::encodeMaxKey): (WebCore::IDBLevelDBCoding::ObjectStoreFreeListKey::encodeMaxKey): (WebCore::IDBLevelDBCoding::IndexFreeListKey::encodeMaxKey):
  • storage/IDBLevelDBCoding.h:

2011-06-03 Hans Wennborg <hans@chromium.org>

Reviewed by Steve Block.

IndexedDB: Clean-up use of INT64_MAX in LevelDB back-end
https://bugs.webkit.org/show_bug.cgi?id=62009

Don't use INT64_MAX, use the various encodeMaxKey() functions instead.

  • tests/IDBLevelDBCodingTest.cpp: (IDBLevelDBCoding::TEST):
  • Property svn:eol-style set to LF
Line 
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 "IDBLevelDBBackingStore.h"
28
29#if ENABLE(INDEXED_DATABASE)
30#if ENABLE(LEVELDB)
31
32#include "Assertions.h"
33#include "FileSystem.h"
34#include "IDBFactoryBackendImpl.h"
35#include "IDBKeyRange.h"
36#include "IDBLevelDBCoding.h"
37#include "LevelDBComparator.h"
38#include "LevelDBDatabase.h"
39#include "LevelDBIterator.h"
40#include "LevelDBSlice.h"
41#include "LevelDBTransaction.h"
42#include "SecurityOrigin.h"
43
44namespace WebCore {
45
46using namespace IDBLevelDBCoding;
47
48template <typename DBOrTransaction>
49static bool getInt(DBOrTransaction* db, const Vector<char>& key, int64_t& foundInt)
50{
51    Vector<char> result;
52    if (!db->get(key, result))
53        return false;
54
55    foundInt = decodeInt(result.begin(), result.end());
56    return true;
57}
58
59template <typename DBOrTransaction>
60static bool putInt(DBOrTransaction* db, const Vector<char>& key, int64_t value)
61{
62    return db->put(key, encodeInt(value));
63}
64
65template <typename DBOrTransaction>
66static bool getString(DBOrTransaction* db, const Vector<char>& key, String& foundString)
67{
68    Vector<char> result;
69    if (!db->get(key, result))
70        return false;
71
72    foundString = decodeString(result.begin(), result.end());
73    return true;
74}
75
76template <typename DBOrTransaction>
77static bool putString(DBOrTransaction* db, const Vector<char> key, const String& value)
78{
79    if (!db->put(key, encodeString(value)))
80        return false;
81    return true;
82}
83
84static int compareKeys(const LevelDBSlice& a, const LevelDBSlice& b)
85{
86    return compare(a, b);
87}
88
89static int compareIndexKeys(const LevelDBSlice& a, const LevelDBSlice& b)
90{
91    return compare(a, b, true);
92}
93
94class Comparator : public LevelDBComparator {
95public:
96    virtual int compare(const LevelDBSlice& a, const LevelDBSlice& b) const { return IDBLevelDBCoding::compare(a, b); }
97    virtual const char* name() const { return "idb_cmp1"; }
98};
99
100static bool setUpMetadata(LevelDBDatabase* db)
101{
102    const Vector<char> metaDataKey = SchemaVersionKey::encode();
103
104    int64_t schemaVersion = 0;
105    if (!getInt(db, metaDataKey, schemaVersion)) {
106        schemaVersion = 0;
107        if (!putInt(db, metaDataKey, schemaVersion))
108            return false;
109    }
110
111    // FIXME: Eventually, we'll need to be able to transition between schemas.
112    if (schemaVersion)
113        return false; // Don't know what to do with this version.
114
115    return true;
116}
117
118IDBLevelDBBackingStore::IDBLevelDBBackingStore(String identifier, IDBFactoryBackendImpl* factory, PassOwnPtr<LevelDBDatabase> db)
119    : m_identifier(identifier)
120    , m_factory(factory)
121    , m_db(db)
122{
123    m_factory->addIDBBackingStore(identifier, this);
124}
125
126IDBLevelDBBackingStore::~IDBLevelDBBackingStore()
127{
128    m_factory->removeIDBBackingStore(m_identifier);
129}
130
131PassRefPtr<IDBBackingStore> IDBLevelDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, int64_t maximumSize, const String& fileIdentifier, IDBFactoryBackendImpl* factory)
132{
133    String pathBase = pathBaseArg;
134
135    if (pathBase.isEmpty()) {
136        ASSERT_NOT_REACHED(); // FIXME: We need to handle this case for incognito and DumpRenderTree.
137        return PassRefPtr<IDBBackingStore>();
138    }
139
140    if (!makeAllDirectories(pathBase)) {
141        LOG_ERROR("Unable to create IndexedDB database path %s", pathBase.utf8().data());
142        return PassRefPtr<IDBBackingStore>();
143    }
144    // FIXME: We should eventually use the same LevelDB database for all origins.
145    String path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb.leveldb");
146
147    OwnPtr<LevelDBComparator> comparator = adoptPtr(new Comparator());
148    OwnPtr<LevelDBDatabase> db = LevelDBDatabase::open(path, comparator.get());
149    if (!db)
150        return PassRefPtr<IDBBackingStore>();
151
152    // FIXME: Handle comparator name changes.
153
154    RefPtr<IDBLevelDBBackingStore> backingStore(adoptRef(new IDBLevelDBBackingStore(fileIdentifier, factory, db.release())));
155    backingStore->m_comparator = comparator.release();
156
157    if (!setUpMetadata(backingStore->m_db.get()))
158        return PassRefPtr<IDBBackingStore>();
159
160    return backingStore.release();
161}
162
163bool IDBLevelDBBackingStore::extractIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId)
164{
165    const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
166
167    bool ok = getInt(m_db.get(), key, foundId);
168    if (!ok)
169        return false;
170
171    ok = getString(m_db.get(), DatabaseMetaDataKey::encode(foundId, DatabaseMetaDataKey::kUserVersion), foundVersion);
172    if (!ok)
173        return false;
174
175    return true;
176}
177
178static int64_t getNewDatabaseId(LevelDBDatabase* db)
179{
180    const Vector<char> freeListStartKey = DatabaseFreeListKey::encode(0);
181    const Vector<char> freeListStopKey = DatabaseFreeListKey::encodeMaxKey();
182
183    OwnPtr<LevelDBIterator> it = db->createIterator();
184    for (it->seek(freeListStartKey); it->isValid() && compareKeys(it->key(), freeListStopKey) < 0; it->next()) {
185        const char *p = it->key().begin();
186        const char *limit = it->key().end();
187
188        DatabaseFreeListKey freeListKey;
189        p = DatabaseFreeListKey::decode(p, limit, &freeListKey);
190        ASSERT(p);
191
192        bool ok = db->remove(it->key());
193        ASSERT_UNUSED(ok, ok);
194
195        return freeListKey.databaseId();
196    }
197
198    // If we got here, there was no free-list.
199    int64_t maxDatabaseId = -1;
200    if (!getInt(db, MaxDatabaseIdKey::encode(), maxDatabaseId))
201        maxDatabaseId = 0;
202
203    ASSERT(maxDatabaseId >= 0);
204
205    int64_t databaseId = maxDatabaseId + 1;
206    bool ok = putInt(db, MaxDatabaseIdKey::encode(), databaseId);
207    ASSERT_UNUSED(ok, ok);
208
209    return databaseId;
210
211}
212
213bool IDBLevelDBBackingStore::setIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId, bool invalidRowId)
214{
215    if (invalidRowId) {
216        rowId = getNewDatabaseId(m_db.get());
217
218        const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
219        if (!putInt(m_db.get(), key, rowId))
220            return false;
221    }
222
223    if (!putString(m_db.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::kUserVersion), version))
224        return false;
225
226    return true;
227}
228
229void IDBLevelDBBackingStore::getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags)
230{
231    const Vector<char> startKey = ObjectStoreMetaDataKey::encode(databaseId, 1, 0);
232    const Vector<char> stopKey = ObjectStoreMetaDataKey::encodeMaxKey(databaseId);
233
234    OwnPtr<LevelDBIterator> it = m_db->createIterator();
235    for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
236        const char *p = it->key().begin();
237        const char *limit = it->key().end();
238
239        ObjectStoreMetaDataKey metaDataKey;
240        p = ObjectStoreMetaDataKey::decode(p, limit, &metaDataKey);
241        ASSERT(p);
242
243        int64_t objectStoreId = metaDataKey.objectStoreId();
244
245        String objectStoreName = decodeString(it->value().begin(), it->value().end());
246
247        it->next();
248        if (!it->isValid()) {
249            LOG_ERROR("Internal Indexed DB error.");
250            return;
251        }
252        String keyPath = decodeString(it->value().begin(), it->value().end());
253
254        it->next();
255        if (!it->isValid()) {
256            LOG_ERROR("Internal Indexed DB error.");
257            return;
258        }
259        bool autoIncrement = *it->value().begin();
260
261        it->next(); // Is evicatble.
262        if (!it->isValid()) {
263            LOG_ERROR("Internal Indexed DB error.");
264            return;
265        }
266
267        it->next(); // Last version.
268        if (!it->isValid()) {
269            LOG_ERROR("Internal Indexed DB error.");
270            return;
271        }
272
273        it->next(); // Maxium index id allocated.
274        if (!it->isValid()) {
275            LOG_ERROR("Internal Indexed DB error.");
276            return;
277        }
278
279        foundIds.append(objectStoreId);
280        foundNames.append(objectStoreName);
281        foundKeyPaths.append(keyPath);
282        foundAutoIncrementFlags.append(autoIncrement);
283    }
284}
285
286static int64_t getNewObjectStoreId(LevelDBTransaction* transaction, int64_t databaseId)
287{
288    const Vector<char> freeListStartKey = ObjectStoreFreeListKey::encode(databaseId, 0);
289    const Vector<char> freeListStopKey = ObjectStoreFreeListKey::encodeMaxKey(databaseId);
290
291    OwnPtr<LevelDBIterator> it = transaction->createIterator();
292    for (it->seek(freeListStartKey); it->isValid() && compareKeys(it->key(), freeListStopKey) < 0; it->next()) {
293        const char* p = it->key().begin();
294        const char* limit = it->key().end();
295
296        ObjectStoreFreeListKey freeListKey;
297        p = ObjectStoreFreeListKey::decode(p, limit, &freeListKey);
298        ASSERT(p);
299
300        bool ok = transaction->remove(it->key());
301        ASSERT_UNUSED(ok, ok);
302
303        return freeListKey.objectStoreId();
304    }
305
306    int64_t maxObjectStoreId = -1;
307    const Vector<char> maxObjectStoreIdKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::kMaxObjectStoreId);
308    if (!getInt(transaction, maxObjectStoreIdKey, maxObjectStoreId))
309        maxObjectStoreId = 0;
310
311    ASSERT(maxObjectStoreId >= 0);
312
313    int64_t objectStoreId = maxObjectStoreId + 1;
314    bool ok = putInt(transaction, maxObjectStoreIdKey, objectStoreId);
315    ASSERT_UNUSED(ok, ok);
316
317    return objectStoreId;
318}
319
320bool IDBLevelDBBackingStore::createObjectStore(int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement, int64_t& assignedObjectStoreId)
321{
322    ASSERT(m_currentTransaction);
323    int64_t objectStoreId = getNewObjectStoreId(m_currentTransaction.get(), databaseId);
324
325    const Vector<char> nameKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0);
326    const Vector<char> keyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 1);
327    const Vector<char> autoIncrementKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 2);
328    const Vector<char> evictableKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 3);
329    const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 4);
330    const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 5);
331    const Vector<char> namesKey = ObjectStoreNamesKey::encode(databaseId, name);
332
333    bool ok = putString(m_currentTransaction.get(), nameKey, name);
334    if (!ok) {
335        LOG_ERROR("Internal Indexed DB error.");
336        return false;
337    }
338
339    ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
340    if (!ok) {
341        LOG_ERROR("Internal Indexed DB error.");
342        return false;
343    }
344
345    ok = putInt(m_currentTransaction.get(), autoIncrementKey, autoIncrement);
346    if (!ok) {
347        LOG_ERROR("Internal Indexed DB error.");
348        return false;
349    }
350
351    ok = putInt(m_currentTransaction.get(), evictableKey, false);
352    if (!ok) {
353        LOG_ERROR("Internal Indexed DB error.");
354        return false;
355    }
356
357    ok = putInt(m_currentTransaction.get(), lastVersionKey, 1);
358    if (!ok) {
359        LOG_ERROR("Internal Indexed DB error.");
360        return false;
361    }
362
363    ok = putInt(m_currentTransaction.get(), maxIndexIdKey, kMinimumIndexId);
364    if (!ok) {
365        LOG_ERROR("Internal Indexed DB error.");
366        return false;
367    }
368
369    ok = putInt(m_currentTransaction.get(), namesKey, objectStoreId);
370    if (!ok) {
371        LOG_ERROR("Internal Indexed DB error.");
372        return false;
373    }
374
375    assignedObjectStoreId = objectStoreId;
376
377    return true;
378}
379
380static bool deleteRange(LevelDBTransaction* transaction, const Vector<char>& begin, const Vector<char>& end)
381{
382    OwnPtr<LevelDBIterator> it = transaction->createIterator();
383    for (it->seek(begin); it->isValid() && compareKeys(it->key(), end) < 0; it->next()) {
384        if (!transaction->remove(it->key()))
385            return false;
386    }
387
388    return true;
389}
390
391void IDBLevelDBBackingStore::deleteObjectStore(int64_t databaseId, int64_t objectStoreId)
392{
393    ASSERT(m_currentTransaction);
394
395    String objectStoreName;
396    getString(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), objectStoreName);
397
398    if (!deleteRange(m_currentTransaction.get(), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 6)))
399        return; // FIXME: Report error.
400
401    putString(m_currentTransaction.get(), ObjectStoreFreeListKey::encode(databaseId, objectStoreId), "");
402    m_currentTransaction->remove(ObjectStoreNamesKey::encode(databaseId, objectStoreName));
403
404    if (!deleteRange(m_currentTransaction.get(), IndexFreeListKey::encode(databaseId, objectStoreId, 0), IndexFreeListKey::encodeMaxKey(databaseId, objectStoreId)))
405        return; // FIXME: Report error.
406    if (!deleteRange(m_currentTransaction.get(), IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0), IndexMetaDataKey::encodeMaxKey(databaseId, objectStoreId)))
407        return; // FIXME: Report error.
408
409    clearObjectStore(databaseId, objectStoreId);
410}
411
412String IDBLevelDBBackingStore::getObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey& key)
413{
414    const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
415    Vector<char> data;
416
417    ASSERT(m_currentTransaction);
418    if (!m_currentTransaction->get(leveldbKey, data))
419        return String();
420
421    int64_t version;
422    const char* p = decodeVarInt(data.begin(), data.end(), version);
423    if (!p)
424        return String();
425    (void) version;
426
427    return decodeString(p, data.end());
428}
429
430namespace {
431class LevelDBRecordIdentifier : public IDBBackingStore::ObjectStoreRecordIdentifier {
432public:
433    static PassRefPtr<LevelDBRecordIdentifier> create(const Vector<char>& primaryKey, int64_t version) { return adoptRef(new LevelDBRecordIdentifier(primaryKey, version)); }
434    static PassRefPtr<LevelDBRecordIdentifier> create() { return adoptRef(new LevelDBRecordIdentifier()); }
435
436    virtual bool isValid() const { return m_primaryKey.isEmpty(); }
437    Vector<char> primaryKey() const { return m_primaryKey; }
438    void setPrimaryKey(const Vector<char>& primaryKey) { m_primaryKey = primaryKey; }
439    int64_t version() const { return m_version; }
440    void setVersion(int64_t version) { m_version = version; }
441
442private:
443    LevelDBRecordIdentifier(const Vector<char>& primaryKey, int64_t version) : m_primaryKey(primaryKey), m_version(version) { ASSERT(!primaryKey.isEmpty()); }
444    LevelDBRecordIdentifier() : m_primaryKey(), m_version(-1) {}
445
446    Vector<char> m_primaryKey; // FIXME: Make it more clear that this is the *encoded* version of the key.
447    int64_t m_version;
448};
449}
450
451static int64_t getNewVersionNumber(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
452{
453    const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 4);
454
455    int64_t lastVersion = -1;
456    if (!getInt(transaction, lastVersionKey, lastVersion))
457        lastVersion = 0;
458
459    ASSERT(lastVersion >= 0);
460
461    int64_t version = lastVersion + 1;
462    bool ok = putInt(transaction, lastVersionKey, version);
463    ASSERT_UNUSED(ok, ok);
464
465    ASSERT(version > lastVersion); // FIXME: Think about how we want to handle the overflow scenario.
466
467    return version;
468}
469
470bool IDBLevelDBBackingStore::putObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, const String& value, ObjectStoreRecordIdentifier* recordIdentifier)
471{
472    ASSERT(m_currentTransaction);
473    int64_t version = getNewVersionNumber(m_currentTransaction.get(), databaseId, objectStoreId);
474    const Vector<char> objectStoredataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
475
476    Vector<char> v;
477    v.append(encodeVarInt(version));
478    v.append(encodeString(value));
479
480    if (!m_currentTransaction->put(objectStoredataKey, v))
481        return false;
482
483    const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, key);
484    if (!m_currentTransaction->put(existsEntryKey, encodeInt(version)))
485        return false;
486
487    LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<LevelDBRecordIdentifier*>(recordIdentifier);
488    levelDBRecordIdentifier->setPrimaryKey(encodeIDBKey(key));
489    levelDBRecordIdentifier->setVersion(version);
490    return true;
491}
492
493void IDBLevelDBBackingStore::clearObjectStore(int64_t databaseId, int64_t objectStoreId)
494{
495    ASSERT(m_currentTransaction);
496    const Vector<char> startKey = KeyPrefix(databaseId, objectStoreId, 0).encode();
497    const Vector<char> stopKey = KeyPrefix(databaseId, objectStoreId + 1, 0).encode();
498
499    deleteRange(m_currentTransaction.get(), startKey, stopKey);
500}
501
502PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> IDBLevelDBBackingStore::createInvalidRecordIdentifier()
503{
504    return LevelDBRecordIdentifier::create();
505}
506
507void IDBLevelDBBackingStore::deleteObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, const ObjectStoreRecordIdentifier* recordIdentifier)
508{
509    ASSERT(m_currentTransaction);
510    const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
511    const Vector<char> key = ObjectStoreDataKey::encode(databaseId, objectStoreId, levelDBRecordIdentifier->primaryKey());
512    m_currentTransaction->remove(key);
513}
514
515double IDBLevelDBBackingStore::nextAutoIncrementNumber(int64_t databaseId, int64_t objectStoreId)
516{
517    ASSERT(m_currentTransaction);
518    const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
519    const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
520
521    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
522
523    int maxNumericKey = 0;
524
525    // FIXME: Be more efficient: seek to something after the object store data, then reverse.
526
527    for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
528        const char *p = it->key().begin();
529        const char *limit = it->key().end();
530
531        ObjectStoreDataKey dataKey;
532        p = ObjectStoreDataKey::decode(p, limit, &dataKey);
533        ASSERT(p);
534
535        if (dataKey.userKey()->type() == IDBKey::NumberType) {
536            int64_t n = static_cast<int64_t>(dataKey.userKey()->number());
537            if (n > maxNumericKey)
538                maxNumericKey = n;
539        }
540    }
541
542    return maxNumericKey + 1;
543}
544
545bool IDBLevelDBBackingStore::keyExistsInObjectStore(int64_t databaseId, int64_t objectStoreId, const IDBKey& key, ObjectStoreRecordIdentifier* foundRecordIdentifier)
546{
547    ASSERT(m_currentTransaction);
548    const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key);
549    Vector<char> data;
550
551    if (!m_currentTransaction->get(leveldbKey, data))
552        return false;
553
554    int64_t version;
555    if (!decodeVarInt(data.begin(), data.end(), version))
556        return false;
557
558    LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<LevelDBRecordIdentifier*>(foundRecordIdentifier);
559    levelDBRecordIdentifier->setPrimaryKey(encodeIDBKey(key));
560    levelDBRecordIdentifier->setVersion(version);
561    return true;
562}
563
564bool IDBLevelDBBackingStore::forEachObjectStoreRecord(int64_t databaseId, int64_t objectStoreId, ObjectStoreRecordCallback& callback)
565{
566    ASSERT(m_currentTransaction);
567    const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
568    const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
569
570    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
571    for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
572        const char *p = it->key().begin();
573        const char *limit = it->key().end();
574        ObjectStoreDataKey dataKey;
575        p = ObjectStoreDataKey::decode(p, limit, &dataKey);
576        ASSERT(p);
577
578        RefPtr<IDBKey> primaryKey = dataKey.userKey();
579
580        int64_t version;
581        const char* q = decodeVarInt(it->value().begin(), it->value().end(), version);
582        if (!q)
583            return false;
584
585        RefPtr<LevelDBRecordIdentifier> ri = LevelDBRecordIdentifier::create(encodeIDBKey(*primaryKey), version);
586        String idbValue = decodeString(q, it->value().end());
587
588        callback.callback(ri.get(), idbValue);
589    }
590
591    return true;
592}
593
594void IDBLevelDBBackingStore::getIndexes(int64_t databaseId, int64_t objectStoreId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<String>& foundKeyPaths, Vector<bool>& foundUniqueFlags)
595{
596    const Vector<char> startKey = IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0);
597    const Vector<char> stopKey = IndexMetaDataKey::encode(databaseId, objectStoreId + 1, 0, 0);
598
599    OwnPtr<LevelDBIterator> it = m_db->createIterator();
600    for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
601        const char* p = it->key().begin();
602        const char* limit = it->key().end();
603
604        IndexMetaDataKey metaDataKey;
605        p = IndexMetaDataKey::decode(p, limit, &metaDataKey);
606        ASSERT(p);
607
608        int64_t indexId = metaDataKey.indexId();
609        ASSERT(!metaDataKey.metaDataType());
610
611        String indexName = decodeString(it->value().begin(), it->value().end());
612        it->next();
613        if (!it->isValid()) {
614            LOG_ERROR("Internal Indexed DB error.");
615            return;
616        }
617
618        bool indexUnique = *it->value().begin();
619        it->next();
620        if (!it->isValid()) {
621            LOG_ERROR("Internal Indexed DB error.");
622            return;
623        }
624
625        String keyPath = decodeString(it->value().begin(), it->value().end());
626
627        foundIds.append(indexId);
628        foundNames.append(indexName);
629        foundKeyPaths.append(keyPath);
630        foundUniqueFlags.append(indexUnique);
631    }
632}
633
634static int64_t getNewIndexId(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId)
635{
636    const Vector<char> startKey = IndexFreeListKey::encode(databaseId, objectStoreId, 0);
637    const Vector<char> stopKey = IndexFreeListKey::encodeMaxKey(databaseId, objectStoreId);
638
639    OwnPtr<LevelDBIterator> it = transaction->createIterator();
640    for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) {
641        const char* p = it->key().begin();
642        const char* limit = it->key().end();
643
644        IndexFreeListKey freeListKey;
645        p = IndexFreeListKey::decode(p, limit, &freeListKey);
646        ASSERT(p);
647
648        bool ok = transaction->remove(it->key());
649        ASSERT_UNUSED(ok, ok);
650
651        ASSERT(freeListKey.indexId() >= kMinimumIndexId);
652        return freeListKey.indexId();
653    }
654
655    int64_t maxIndexId = -1;
656    const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 5);
657    if (!getInt(transaction, maxIndexIdKey, maxIndexId))
658        maxIndexId = kMinimumIndexId;
659
660    ASSERT(maxIndexId >= 0);
661
662    int64_t indexId = maxIndexId + 1;
663    bool ok = putInt(transaction, maxIndexIdKey, indexId);
664    if (!ok)
665        return false;
666
667    return indexId;
668}
669
670bool IDBLevelDBBackingStore::createIndex(int64_t databaseId, int64_t objectStoreId, const String& name, const String& keyPath, bool isUnique, int64_t& indexId)
671{
672    ASSERT(m_currentTransaction);
673    indexId = getNewIndexId(m_currentTransaction.get(), databaseId, objectStoreId);
674
675    const Vector<char> nameKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 0);
676    const Vector<char> uniqueKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 1);
677    const Vector<char> keyPathKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 2);
678
679    bool ok = putString(m_currentTransaction.get(), nameKey, name);
680    if (!ok) {
681        LOG_ERROR("Internal Indexed DB error.");
682        return false;
683    }
684
685    ok = putInt(m_currentTransaction.get(), uniqueKey, isUnique);
686    if (!ok) {
687        LOG_ERROR("Internal Indexed DB error.");
688        return false;
689    }
690
691    ok = putString(m_currentTransaction.get(), keyPathKey, keyPath);
692    if (!ok) {
693        LOG_ERROR("Internal Indexed DB error.");
694        return false;
695    }
696
697    return true;
698}
699
700void IDBLevelDBBackingStore::deleteIndex(int64_t, int64_t, int64_t)
701{
702    ASSERT_NOT_REACHED(); // FIXME: Implement and add layout test.
703    return;
704}
705
706bool IDBLevelDBBackingStore::putIndexDataForRecord(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, const ObjectStoreRecordIdentifier* recordIdentifier)
707{
708    ASSERT(indexId >= kMinimumIndexId);
709    const LevelDBRecordIdentifier* levelDBRecordIdentifier = static_cast<const LevelDBRecordIdentifier*>(recordIdentifier);
710
711    ASSERT(m_currentTransaction);
712    const int64_t globalSequenceNumber = getNewVersionNumber(m_currentTransaction.get(), databaseId, objectStoreId);
713    const Vector<char> indexDataKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, globalSequenceNumber);
714
715    Vector<char> data;
716    data.append(encodeVarInt(levelDBRecordIdentifier->version()));
717    data.append(levelDBRecordIdentifier->primaryKey());
718
719    return m_currentTransaction->put(indexDataKey, data);
720}
721
722static bool findGreatestKeyLessThan(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey)
723{
724    OwnPtr<LevelDBIterator> it = transaction->createIterator();
725    it->seek(target);
726
727    if (!it->isValid()) {
728        it->seekToLast();
729        if (!it->isValid())
730            return false;
731    }
732
733    while (compareIndexKeys(it->key(), target) >= 0) {
734        it->prev();
735        if (!it->isValid())
736            return false;
737    }
738
739    foundKey.clear();
740    foundKey.append(it->key().begin(), it->key().end() - it->key().begin());
741    return true;
742}
743
744bool IDBLevelDBBackingStore::deleteIndexDataForRecord(int64_t, int64_t, int64_t, const ObjectStoreRecordIdentifier*)
745{
746    // FIXME: This isn't needed since we invalidate index data via the version number mechanism.
747    return true;
748}
749
750String IDBLevelDBBackingStore::getObjectViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
751{
752    RefPtr<IDBKey> primaryKey = getPrimaryKeyViaIndex(databaseId, objectStoreId, indexId, key);
753    if (!primaryKey)
754        return String();
755
756    return getObjectStoreRecord(databaseId, objectStoreId, *primaryKey);
757}
758
759static bool versionExists(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t version, const Vector<char>& encodedPrimaryKey)
760{
761    const Vector<char> key = ExistsEntryKey::encode(databaseId, objectStoreId, encodedPrimaryKey);
762    Vector<char> data;
763
764    if (!transaction->get(key, data))
765        return false;
766
767    return decodeInt(data.begin(), data.end()) == version;
768}
769
770PassRefPtr<IDBKey> IDBLevelDBBackingStore::getPrimaryKeyViaIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
771{
772    ASSERT(m_currentTransaction);
773    const Vector<char> leveldbKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, 0);
774    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
775    it->seek(leveldbKey);
776
777    for (;;) {
778        if (!it->isValid())
779            return 0;
780        if (compareIndexKeys(it->key(), leveldbKey) > 0)
781            return 0;
782
783        int64_t version;
784        const char* p = decodeVarInt(it->value().begin(), it->value().end(), version);
785        if (!p)
786            return 0;
787        Vector<char> encodedPrimaryKey;
788        encodedPrimaryKey.append(p, it->value().end() - p);
789
790        if (!versionExists(m_currentTransaction.get(), databaseId, objectStoreId, version, encodedPrimaryKey)) {
791            // Delete stale index data entry and continue.
792            m_currentTransaction->remove(it->key());
793            it->next();
794            continue;
795        }
796
797        RefPtr<IDBKey> primaryKey;
798        decodeIDBKey(encodedPrimaryKey.begin(), encodedPrimaryKey.end(), primaryKey);
799        return primaryKey.release();
800    }
801}
802
803bool IDBLevelDBBackingStore::keyExistsInIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key)
804{
805    ASSERT(m_currentTransaction);
806    const Vector<char> levelDBKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key, 0);
807    OwnPtr<LevelDBIterator> it = m_currentTransaction->createIterator();
808
809    bool found = false;
810
811    it->seek(levelDBKey);
812    if (it->isValid() && !compareIndexKeys(it->key(), levelDBKey))
813        found = true;
814
815    return found;
816}
817
818namespace {
819class CursorImplCommon : public IDBBackingStore::Cursor {
820public:
821    // IDBBackingStore::Cursor
822    virtual bool continueFunction(const IDBKey*);
823    virtual PassRefPtr<IDBKey> key() { return m_currentKey; }
824    virtual PassRefPtr<IDBKey> primaryKey() { return m_currentKey; }
825    virtual String value() = 0;
826    virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() = 0; // FIXME: I don't think this is actually used, so drop it.
827    virtual int64_t indexDataId() = 0;
828    virtual void close() { }
829
830    virtual bool loadCurrentRow() = 0;
831    bool firstSeek();
832
833protected:
834    CursorImplCommon(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
835        : m_transaction(transaction)
836        , m_lowKey(lowKey)
837        , m_lowOpen(lowOpen)
838        , m_highKey(highKey)
839        , m_highOpen(highOpen)
840        , m_forward(forward)
841        , m_unique(unique)
842    {
843    }
844    virtual ~CursorImplCommon() {}
845
846    LevelDBTransaction* m_transaction;
847    OwnPtr<LevelDBIterator> m_iterator;
848    Vector<char> m_lowKey;
849    bool m_lowOpen;
850    Vector<char> m_highKey;
851    bool m_highOpen;
852    bool m_forward;
853    bool m_unique;
854    RefPtr<IDBKey> m_currentKey;
855};
856
857bool CursorImplCommon::firstSeek()
858{
859    m_iterator = m_transaction->createIterator();
860
861    if (m_forward)
862        m_iterator->seek(m_lowKey);
863    else
864        m_iterator->seek(m_highKey);
865
866    for (;;) {
867        if (!m_iterator->isValid())
868            return false;
869
870        if (m_forward && m_highOpen && compareIndexKeys(m_iterator->key(), m_highKey) >= 0)
871            return false;
872        if (m_forward && !m_highOpen && compareIndexKeys(m_iterator->key(), m_highKey) > 0)
873            return false;
874        if (!m_forward && m_lowOpen && compareIndexKeys(m_iterator->key(), m_lowKey) <= 0)
875            return false;
876        if (!m_forward && !m_lowOpen && compareIndexKeys(m_iterator->key(), m_lowKey) < 0)
877            return false;
878
879        if (m_forward && m_lowOpen) {
880            // lowKey not included in the range.
881            if (compareIndexKeys(m_iterator->key(), m_lowKey) <= 0) {
882                m_iterator->next();
883                continue;
884            }
885        }
886        if (!m_forward && m_highOpen) {
887            // highKey not included in the range.
888            if (compareIndexKeys(m_iterator->key(), m_highKey) >= 0) {
889                m_iterator->prev();
890                continue;
891            }
892        }
893
894        if (!loadCurrentRow()) {
895            if (m_forward)
896                m_iterator->next();
897            else
898                m_iterator->prev();
899            continue;
900        }
901
902        return true;
903    }
904}
905
906bool CursorImplCommon::continueFunction(const IDBKey* key)
907{
908    // FIXME: This shares a lot of code with firstSeek.
909    RefPtr<IDBKey> previousKey = m_currentKey;
910
911    for (;;) {
912        if (m_forward)
913            m_iterator->next();
914        else
915            m_iterator->prev();
916
917        if (!m_iterator->isValid())
918            return false;
919
920        Vector<char> trash;
921        if (!m_transaction->get(m_iterator->key(), trash))
922             continue;
923
924        if (m_forward && m_highOpen && compareIndexKeys(m_iterator->key(), m_highKey) >= 0) // high key not included in range
925            return false;
926        if (m_forward && !m_highOpen && compareIndexKeys(m_iterator->key(), m_highKey) > 0)
927            return false;
928        if (!m_forward && m_lowOpen && compareIndexKeys(m_iterator->key(), m_lowKey) <= 0) // low key not included in range
929            return false;
930        if (!m_forward && !m_lowOpen && compareIndexKeys(m_iterator->key(), m_lowKey) < 0)
931            return false;
932
933        if (!loadCurrentRow())
934            continue;
935
936        if (key) {
937            if (m_forward) {
938                if (m_currentKey->isLessThan(key))
939                    continue;
940            } else {
941                if (key->isLessThan(m_currentKey.get()))
942                    continue;
943            }
944        }
945
946        if (m_unique && m_currentKey->isEqual(previousKey.get()))
947            continue;
948
949        break;
950    }
951
952    return true;
953}
954
955class ObjectStoreCursorImpl : public CursorImplCommon {
956public:
957    static PassRefPtr<ObjectStoreCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
958    {
959        return adoptRef(new ObjectStoreCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique));
960    }
961
962    // CursorImplCommon
963    virtual String value() { return m_currentValue; }
964    virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() { ASSERT_NOT_REACHED(); return 0; }
965    virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
966    virtual bool loadCurrentRow();
967
968private:
969    ObjectStoreCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
970        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique)
971    {
972    }
973
974    String m_currentValue;
975};
976
977bool ObjectStoreCursorImpl::loadCurrentRow()
978{
979    const char* p = m_iterator->key().begin();
980    const char* keyLimit = m_iterator->key().end();
981
982    ObjectStoreDataKey objectStoreDataKey;
983    p = ObjectStoreDataKey::decode(p, keyLimit, &objectStoreDataKey);
984    ASSERT(p);
985    if (!p)
986        return false;
987
988    m_currentKey = objectStoreDataKey.userKey();
989
990    int64_t version;
991    const char* q = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), version);
992    ASSERT(q);
993    if (!q)
994        return false;
995    (void) version;
996
997    m_currentValue = decodeString(q, m_iterator->value().end());
998
999    return true;
1000}
1001
1002class IndexKeyCursorImpl : public CursorImplCommon {
1003public:
1004    static PassRefPtr<IndexKeyCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
1005    {
1006        return adoptRef(new IndexKeyCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique));
1007    }
1008
1009    // CursorImplCommon
1010    virtual String value() { ASSERT_NOT_REACHED(); return String(); }
1011    virtual PassRefPtr<IDBKey> primaryKey() { return m_primaryKey; }
1012    virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() { ASSERT_NOT_REACHED(); return 0; }
1013    virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
1014    virtual bool loadCurrentRow();
1015
1016private:
1017    IndexKeyCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
1018        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique)
1019    {
1020    }
1021
1022    RefPtr<IDBKey> m_primaryKey;
1023};
1024
1025bool IndexKeyCursorImpl::loadCurrentRow()
1026{
1027    const char* p = m_iterator->key().begin();
1028    const char* keyLimit = m_iterator->key().end();
1029    IndexDataKey indexDataKey;
1030    p = IndexDataKey::decode(p, keyLimit, &indexDataKey);
1031
1032    m_currentKey = indexDataKey.userKey();
1033
1034    int64_t indexDataVersion;
1035    const char* q = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), indexDataVersion);
1036    ASSERT(q);
1037    if (!q)
1038        return false;
1039
1040    q = decodeIDBKey(q, m_iterator->value().end(), m_primaryKey);
1041    ASSERT(q);
1042    if (!q)
1043        return false;
1044
1045    Vector<char> primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
1046
1047    Vector<char> result;
1048    if (!m_transaction->get(primaryLevelDBKey, result))
1049        return false;
1050
1051    int64_t objectStoreDataVersion;
1052    const char* t = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion);
1053    ASSERT(t);
1054    if (!t)
1055        return false;
1056
1057    if (objectStoreDataVersion != indexDataVersion) { // FIXME: This is probably not very well covered by the layout tests.
1058        m_transaction->remove(m_iterator->key());
1059        return false;
1060    }
1061
1062    return true;
1063}
1064
1065class IndexCursorImpl : public CursorImplCommon {
1066public:
1067    static PassRefPtr<IndexCursorImpl> create(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
1068    {
1069        return adoptRef(new IndexCursorImpl(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique));
1070    }
1071
1072    // CursorImplCommon
1073    virtual String value() { return m_value; }
1074    virtual PassRefPtr<IDBKey> primaryKey() { return m_primaryKey; }
1075    virtual PassRefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> objectStoreRecordIdentifier() { ASSERT_NOT_REACHED(); return 0; }
1076    virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
1077    bool loadCurrentRow();
1078
1079private:
1080    IndexCursorImpl(LevelDBTransaction* transaction, const Vector<char>& lowKey, bool lowOpen, const Vector<char>& highKey, bool highOpen, bool forward, bool unique)
1081        : CursorImplCommon(transaction, lowKey, lowOpen, highKey, highOpen, forward, unique)
1082    {
1083    }
1084
1085    RefPtr<IDBKey> m_primaryKey;
1086    String m_value;
1087    Vector<char> m_primaryLevelDBKey;
1088};
1089
1090bool IndexCursorImpl::loadCurrentRow()
1091{
1092    const char *p = m_iterator->key().begin();
1093    const char *limit = m_iterator->key().end();
1094
1095    IndexDataKey indexDataKey;
1096    p = IndexDataKey::decode(p, limit, &indexDataKey);
1097
1098    m_currentKey = indexDataKey.userKey();
1099
1100    const char *q = m_iterator->value().begin();
1101    const char *valueLimit = m_iterator->value().end();
1102
1103    int64_t indexDataVersion;
1104    q = decodeVarInt(q, valueLimit, indexDataVersion);
1105    ASSERT(q);
1106    if (!q)
1107        return false;
1108    q = decodeIDBKey(q, valueLimit, m_primaryKey);
1109    ASSERT(q);
1110    if (!q)
1111        return false;
1112
1113    m_primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey);
1114
1115    Vector<char> result;
1116    if (!m_transaction->get(m_primaryLevelDBKey, result))
1117        return false;
1118
1119    int64_t objectStoreDataVersion;
1120    const char* t = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion);
1121    ASSERT(t);
1122    if (!t)
1123        return false;
1124
1125    if (objectStoreDataVersion != indexDataVersion) {
1126        m_transaction->remove(m_iterator->key());
1127        return false;
1128    }
1129
1130    m_value = decodeString(t, result.end());
1131    return true;
1132}
1133
1134}
1135
1136static bool findLastIndexKeyEqualTo(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey)
1137{
1138    OwnPtr<LevelDBIterator> it = transaction->createIterator();
1139    it->seek(target);
1140
1141    if (!it->isValid())
1142        return false;
1143
1144    while (it->isValid() && !compareIndexKeys(it->key(), target)) {
1145        foundKey.clear();
1146        foundKey.append(it->key().begin(), it->key().end() - it->key().begin());
1147        it->next();
1148    }
1149
1150    return true;
1151}
1152
1153PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openObjectStoreCursor(int64_t databaseId, int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction)
1154{
1155    ASSERT(m_currentTransaction);
1156    bool lowerBound = range && range->lower();
1157    bool upperBound = range && range->upper();
1158    bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1159    bool unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1160
1161    bool lowerOpen, upperOpen;
1162    Vector<char> startKey, stopKey;
1163
1164    if (!lowerBound) {
1165        startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey());
1166        lowerOpen = true; // Not included.
1167    } else {
1168        startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->lower());
1169        lowerOpen = range->lowerOpen();
1170    }
1171
1172    if (!upperBound) {
1173        stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey());
1174        upperOpen = true; // Not included.
1175
1176        if (!forward) { // We need a key that exists.
1177            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
1178                return 0;
1179            upperOpen = false;
1180        }
1181    } else {
1182        stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->upper());
1183        upperOpen = range->upperOpen();
1184    }
1185
1186    RefPtr<ObjectStoreCursorImpl> cursor = ObjectStoreCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward, unique);
1187    if (!cursor->firstSeek())
1188        return 0;
1189
1190    return cursor.release();
1191}
1192
1193PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexKeyCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
1194{
1195    ASSERT(m_currentTransaction);
1196    bool lowerBound = range && range->lower();
1197    bool upperBound = range && range->upper();
1198    bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1199    bool unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1200
1201    bool lowerOpen, upperOpen;
1202    Vector<char> startKey, stopKey;
1203
1204    if (!lowerBound) {
1205        startKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, minIDBKey(), 0);
1206        lowerOpen = false; // Included.
1207    } else {
1208        startKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->lower(), 0);
1209        lowerOpen = range->lowerOpen();
1210    }
1211
1212    if (!upperBound) {
1213        stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, maxIDBKey(), 0);
1214        upperOpen = false; // Included.
1215
1216        if (!forward) { // We need a key that exists.
1217            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
1218                return 0;
1219            upperOpen = false;
1220        }
1221    } else {
1222        stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper(), 0);
1223        if (!findLastIndexKeyEqualTo(m_currentTransaction.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
1224            return 0;
1225        upperOpen = range->upperOpen();
1226    }
1227
1228    RefPtr<IndexKeyCursorImpl> cursor = IndexKeyCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward, unique);
1229    if (!cursor->firstSeek())
1230        return 0;
1231
1232    return cursor.release();
1233}
1234
1235PassRefPtr<IDBBackingStore::Cursor> IDBLevelDBBackingStore::openIndexCursor(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
1236{
1237    ASSERT(m_currentTransaction);
1238    bool lowerBound = range && range->lower();
1239    bool upperBound = range && range->upper();
1240    bool forward = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::NEXT);
1241    bool unique = (direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE);
1242
1243    bool lowerOpen, upperOpen;
1244    Vector<char> startKey, stopKey;
1245
1246    if (!lowerBound) {
1247        startKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, minIDBKey(), 0);
1248        lowerOpen = false; // Included.
1249    } else {
1250        startKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->lower(), 0);
1251        lowerOpen = range->lowerOpen();
1252    }
1253
1254    if (!upperBound) {
1255        stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, maxIDBKey(), 0);
1256        upperOpen = false; // Included.
1257
1258        if (!forward) { // We need a key that exists.
1259            if (!findGreatestKeyLessThan(m_currentTransaction.get(), stopKey, stopKey))
1260                return 0;
1261            upperOpen = false;
1262        }
1263    } else {
1264        stopKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper(), 0);
1265        if (!findLastIndexKeyEqualTo(m_currentTransaction.get(), stopKey, stopKey)) // Seek to the *last* key in the set of non-unique keys.
1266            return 0;
1267        upperOpen = range->upperOpen();
1268    }
1269
1270    RefPtr<IndexCursorImpl> cursor = IndexCursorImpl::create(m_currentTransaction.get(), startKey, lowerOpen, stopKey, upperOpen, forward, unique);
1271    if (!cursor->firstSeek())
1272        return 0;
1273
1274    return cursor.release();
1275}
1276
1277PassRefPtr<IDBBackingStore::Transaction> IDBLevelDBBackingStore::createTransaction()
1278{
1279    return Transaction::create(this);
1280}
1281
1282PassRefPtr<IDBLevelDBBackingStore::Transaction> IDBLevelDBBackingStore::Transaction::create(IDBLevelDBBackingStore* backingStore)
1283{
1284    return adoptRef(new Transaction(backingStore));
1285}
1286
1287IDBLevelDBBackingStore::Transaction::Transaction(IDBLevelDBBackingStore* backingStore)
1288    : m_backingStore(backingStore)
1289{
1290}
1291
1292void IDBLevelDBBackingStore::Transaction::begin()
1293{
1294    ASSERT(!m_backingStore->m_currentTransaction);
1295    m_backingStore->m_currentTransaction = LevelDBTransaction::create(m_backingStore->m_db.get());
1296}
1297
1298void IDBLevelDBBackingStore::Transaction::commit()
1299{
1300    ASSERT(m_backingStore->m_currentTransaction);
1301    m_backingStore->m_currentTransaction->commit();
1302    m_backingStore->m_currentTransaction.clear();
1303}
1304
1305void IDBLevelDBBackingStore::Transaction::rollback()
1306{
1307    ASSERT(m_backingStore->m_currentTransaction);
1308    m_backingStore->m_currentTransaction->rollback();
1309    m_backingStore->m_currentTransaction.clear();
1310}
1311
1312// FIXME: deleteDatabase should be part of IDBBackingStore.
1313
1314} // namespace WebCore
1315
1316#endif // ENABLE(LEVELDB)
1317#endif // ENABLE(INDEXED_DATABASE)
Note: See TracBrowser for help on using the repository browser.