OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
(...skipping 3156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3167 if (!Continue(s)) | 3167 if (!Continue(s)) |
3168 return false; | 3168 return false; |
3169 } | 3169 } |
3170 return true; | 3170 return true; |
3171 } | 3171 } |
3172 | 3172 |
3173 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key, | 3173 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key, |
3174 const IndexedDBKey* primary_key, | 3174 const IndexedDBKey* primary_key, |
3175 IteratorState next_state, | 3175 IteratorState next_state, |
3176 leveldb::Status* s) { | 3176 leveldb::Status* s) { |
| 3177 DCHECK(!key || next_state == SEEK); |
| 3178 |
| 3179 if (cursor_options_.forward) |
| 3180 return ContinueNext(key, primary_key, next_state, s); |
| 3181 else |
| 3182 return ContinuePrevious(key, primary_key, next_state, s); |
| 3183 } |
| 3184 |
| 3185 bool IndexedDBBackingStore::Cursor::ContinueNext( |
| 3186 const IndexedDBKey* key, |
| 3187 const IndexedDBKey* primary_key, |
| 3188 IteratorState next_state, |
| 3189 leveldb::Status* s) { |
| 3190 DCHECK(cursor_options_.forward); |
3177 DCHECK(!key || key->IsValid()); | 3191 DCHECK(!key || key->IsValid()); |
3178 DCHECK(!primary_key || primary_key->IsValid()); | 3192 DCHECK(!primary_key || primary_key->IsValid()); |
3179 *s = leveldb::Status::OK(); | 3193 *s = leveldb::Status::OK(); |
3180 | 3194 |
3181 // TODO(alecflett): avoid a copy here? | 3195 // TODO(alecflett): avoid a copy here? |
3182 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); | 3196 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); |
3183 | 3197 |
3184 // When iterating with PrevNoDuplicate, spec requires that the | 3198 // Optimization: if seeking to a particular key (or key and primary key), |
3185 // value we yield for each key is the first duplicate in forwards | 3199 // skip the cursor forward rather than iterating it. |
3186 // order. | 3200 if (next_state == SEEK && key) { |
| 3201 std::string leveldb_key = |
| 3202 primary_key ? EncodeKey(*key, *primary_key) : EncodeKey(*key); |
| 3203 *s = iterator_->Seek(leveldb_key); |
| 3204 if (!s->ok()) |
| 3205 return false; |
| 3206 // Cursor is at the next value already; don't advance it again below. |
| 3207 next_state = READY; |
| 3208 } |
| 3209 |
| 3210 for (;;) { |
| 3211 // Only advance the cursor if it was not set to position already, |
| 3212 // either because it is newly opened (and positioned at start of range) |
| 3213 // or skipped forward by continue with a specific key. |
| 3214 if (next_state == SEEK) { |
| 3215 *s = iterator_->Next(); |
| 3216 if (!s->ok()) |
| 3217 return false; |
| 3218 } else { |
| 3219 next_state = SEEK; |
| 3220 } |
| 3221 |
| 3222 // TODO(jsbell): Can we DCHECK iterator_->IsValid() up top? |
| 3223 // Fail if we've run out of data or gone past the cursor's bounds. |
| 3224 if (!iterator_->IsValid() || IsPastBounds()) |
| 3225 return false; |
| 3226 |
| 3227 // TODO(jsbell): Document why this might be false. When do we ever not |
| 3228 // seek into the range before starting cursor iteration? |
| 3229 if (!HaveEnteredRange()) |
| 3230 continue; |
| 3231 |
| 3232 // The row may not load because there's a stale entry in the |
| 3233 // index. If no error then not fatal. |
| 3234 if (!LoadCurrentRow(s)) { |
| 3235 if (!s->ok()) |
| 3236 return false; |
| 3237 continue; |
| 3238 } |
| 3239 |
| 3240 // If seeking to a key (or key and primary key), continue until found. |
| 3241 // TODO(jsbell): Given the Seek() optimization above, this should |
| 3242 // not be necessary. Verify and remove. |
| 3243 if (key) { |
| 3244 if (primary_key && current_key_->Equals(*key) && |
| 3245 this->primary_key().IsLessThan(*primary_key)) |
| 3246 continue; |
| 3247 if (current_key_->IsLessThan(*key)) |
| 3248 continue; |
| 3249 } |
| 3250 |
| 3251 // Cursor is now positioned at a non-stale record in range. |
| 3252 |
| 3253 // "Unique" cursors should continue seeking until a new key value is seen. |
| 3254 if (cursor_options_.unique && previous_key.IsValid() && |
| 3255 current_key_->Equals(previous_key)) { |
| 3256 continue; |
| 3257 } |
| 3258 |
| 3259 break; |
| 3260 } |
| 3261 |
| 3262 return true; |
| 3263 } |
| 3264 |
| 3265 bool IndexedDBBackingStore::Cursor::ContinuePrevious( |
| 3266 const IndexedDBKey* key, |
| 3267 const IndexedDBKey* primary_key, |
| 3268 IteratorState next_state, |
| 3269 leveldb::Status* s) { |
| 3270 DCHECK(!cursor_options_.forward); |
| 3271 DCHECK(!key || key->IsValid()); |
| 3272 DCHECK(!primary_key || primary_key->IsValid()); |
| 3273 *s = leveldb::Status::OK(); |
| 3274 |
| 3275 // TODO(alecflett): avoid a copy here? |
| 3276 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); |
| 3277 |
| 3278 // When iterating with PrevNoDuplicate, spec requires that the value we |
| 3279 // yield for each key is the *first* duplicate in forwards order. We do this |
| 3280 // by remembering the *last* duplicate seen (implicitly, the first value |
| 3281 // seen with a new key), continuing until another new key is seen, then |
| 3282 // reversing until we find a key equal to the *last* duplicate. |
3187 IndexedDBKey last_duplicate_key; | 3283 IndexedDBKey last_duplicate_key; |
| 3284 bool find_first_duplicate = false; |
3188 | 3285 |
3189 bool forward = cursor_options_.forward; | 3286 // TODO(jsbell): Optimize continuing to a specific key (or key and primary |
3190 bool first_iteration_forward = forward; | 3287 // key) for reverse cursors as well. See Seek() optimization at the start |
3191 bool flipped = false; | 3288 // of ContinueNext() for an example. |
3192 | 3289 |
3193 for (;;) { | 3290 for (;;) { |
3194 if (next_state == SEEK) { | 3291 if (next_state == SEEK) { |
3195 // TODO(jsbell): Optimize seeking for reverse cursors as well. | 3292 *s = iterator_->Prev(); |
3196 if (first_iteration_forward && key) { | |
3197 first_iteration_forward = false; | |
3198 std::string leveldb_key; | |
3199 if (primary_key) { | |
3200 leveldb_key = EncodeKey(*key, *primary_key); | |
3201 } else { | |
3202 leveldb_key = EncodeKey(*key); | |
3203 } | |
3204 *s = iterator_->Seek(leveldb_key); | |
3205 } else if (forward) { | |
3206 *s = iterator_->Next(); | |
3207 } else { | |
3208 *s = iterator_->Prev(); | |
3209 } | |
3210 if (!s->ok()) | 3293 if (!s->ok()) |
3211 return false; | 3294 return false; |
3212 } else { | 3295 } else { |
3213 next_state = SEEK; // for subsequent iterations | 3296 next_state = SEEK; // for subsequent iterations |
3214 } | 3297 } |
3215 | 3298 |
3216 if (!iterator_->IsValid()) { | 3299 // If we've run out of data or gone past the cursor's bounds. |
3217 if (!forward && last_duplicate_key.IsValid()) { | 3300 if (!iterator_->IsValid() || IsPastBounds()) { |
3218 // We need to walk forward because we hit the end of | 3301 if (last_duplicate_key.IsValid()) { |
3219 // the data. | 3302 // Walk the cursor forward to the first duplicate. |
3220 forward = true; | 3303 find_first_duplicate = true; |
3221 flipped = true; | 3304 break; |
3222 continue; | |
3223 } | 3305 } |
3224 | 3306 |
3225 return false; | 3307 return false; |
3226 } | 3308 } |
3227 | 3309 |
3228 if (IsPastBounds()) { | 3310 // TODO(jsbell): Document why this might be false. When do we ever not |
3229 if (!forward && last_duplicate_key.IsValid()) { | 3311 // seek into the range before starting cursor iteration? |
3230 // We need to walk forward because now we're beyond the | |
3231 // bounds defined by the cursor. | |
3232 forward = true; | |
3233 flipped = true; | |
3234 continue; | |
3235 } | |
3236 | |
3237 return false; | |
3238 } | |
3239 | |
3240 if (!HaveEnteredRange()) | 3312 if (!HaveEnteredRange()) |
3241 continue; | 3313 continue; |
3242 | 3314 |
3243 // The row may not load because there's a stale entry in the | 3315 // The row may not load because there's a stale entry in the |
3244 // index. If no error then not fatal. | 3316 // index. If no error then not fatal. |
3245 if (!LoadCurrentRow(s)) { | 3317 if (!LoadCurrentRow(s)) { |
3246 if (!s->ok()) | 3318 if (!s->ok()) |
3247 return false; | 3319 return false; |
3248 continue; | 3320 continue; |
3249 } | 3321 } |
3250 | 3322 |
| 3323 // If seeking to a key (or key and primary key), continue until found. |
| 3324 // TODO(jsbell): If Seek() optimization is added above, remove this. |
3251 if (key) { | 3325 if (key) { |
3252 if (forward) { | 3326 if (primary_key && key->Equals(*current_key_) && |
3253 if (primary_key && current_key_->Equals(*key) && | 3327 primary_key->IsLessThan(this->primary_key())) |
3254 this->primary_key().IsLessThan(*primary_key)) | 3328 continue; |
3255 continue; | 3329 if (key->IsLessThan(*current_key_)) |
3256 if (!flipped && current_key_->IsLessThan(*key)) | 3330 continue; |
3257 continue; | |
3258 } else { | |
3259 if (primary_key && key->Equals(*current_key_) && | |
3260 primary_key->IsLessThan(this->primary_key())) | |
3261 continue; | |
3262 if (key->IsLessThan(*current_key_)) | |
3263 continue; | |
3264 } | |
3265 } | 3331 } |
3266 | 3332 |
| 3333 // Cursor is now positioned at a non-stale record in range. |
| 3334 |
3267 if (cursor_options_.unique) { | 3335 if (cursor_options_.unique) { |
3268 if (previous_key.IsValid() && current_key_->Equals(previous_key)) { | 3336 // If entry is a duplicate, keep going. Although the cursor should be |
3269 // We should never be able to walk forward all the way | 3337 // positioned at the first duplicate already, new duplicates may have |
3270 // to the previous key. | 3338 // been inserted since the cursor was last iterated, and should be |
3271 DCHECK(!last_duplicate_key.IsValid()); | 3339 // skipped to maintain "unique" iteration. |
| 3340 if (previous_key.IsValid() && current_key_->Equals(previous_key)) |
| 3341 continue; |
| 3342 |
| 3343 // If we've found a new key, remember it and keep going. |
| 3344 if (!last_duplicate_key.IsValid()) { |
| 3345 last_duplicate_key = *current_key_; |
3272 continue; | 3346 continue; |
3273 } | 3347 } |
3274 | 3348 |
3275 if (!forward) { | 3349 // If we're still seeing duplicates, keep going. |
3276 if (!last_duplicate_key.IsValid()) { | 3350 if (last_duplicate_key.Equals(*current_key_)) |
3277 last_duplicate_key = *current_key_; | 3351 continue; |
3278 continue; | |
3279 } | |
3280 | 3352 |
3281 // We need to walk forward because we hit the boundary | 3353 // Walk the cursor forward to the first duplicate. |
3282 // between key ranges. | 3354 find_first_duplicate = true; |
3283 if (!last_duplicate_key.Equals(*current_key_)) { | 3355 } |
3284 forward = true; | |
3285 flipped = true; | |
3286 continue; | |
3287 } | |
3288 | 3356 |
3289 continue; | |
3290 } | |
3291 } | |
3292 break; | 3357 break; |
3293 } | 3358 } |
3294 | 3359 |
| 3360 // TODO(jsbell): Rather than iterating, stash the last leveldb key of the |
| 3361 // last plausible result, then Seek() the cursor directly to that and |
| 3362 // LoadCurrentRow(). |
| 3363 |
| 3364 if (find_first_duplicate) { |
| 3365 DCHECK_EQ(next_state, SEEK); |
| 3366 DCHECK(cursor_options_.unique); |
| 3367 for (;;) { |
| 3368 *s = iterator_->Next(); |
| 3369 if (!s->ok() || !iterator_->IsValid() || IsPastBounds()) |
| 3370 return false; |
| 3371 |
| 3372 // TODO(jsbell): Document why this might be false. When do we ever not |
| 3373 // seek into the range before starting cursor iteration? |
| 3374 if (!HaveEnteredRange()) |
| 3375 continue; |
| 3376 |
| 3377 // The row may not load because there's a stale entry in the |
| 3378 // index. If no error then not fatal. |
| 3379 if (!LoadCurrentRow(s)) { |
| 3380 if (!s->ok()) |
| 3381 return false; |
| 3382 continue; |
| 3383 } |
| 3384 |
| 3385 break; |
| 3386 } |
| 3387 } |
| 3388 |
3295 DCHECK(!last_duplicate_key.IsValid() || | 3389 DCHECK(!last_duplicate_key.IsValid() || |
3296 (forward && last_duplicate_key.Equals(*current_key_))); | 3390 (find_first_duplicate && last_duplicate_key.Equals(*current_key_))); |
3297 return true; | 3391 return true; |
3298 } | 3392 } |
3299 | 3393 |
3300 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { | 3394 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { |
3301 if (cursor_options_.forward) { | 3395 if (cursor_options_.forward) { |
3302 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); | 3396 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); |
3303 if (cursor_options_.low_open) { | 3397 if (cursor_options_.low_open) { |
3304 return compare > 0; | 3398 return compare > 0; |
3305 } | 3399 } |
3306 return compare >= 0; | 3400 return compare >= 0; |
(...skipping 1125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4432 | 4526 |
4433 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | 4527 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
4434 const WriteDescriptor& other) = default; | 4528 const WriteDescriptor& other) = default; |
4435 IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() = | 4529 IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() = |
4436 default; | 4530 default; |
4437 IndexedDBBackingStore::Transaction::WriteDescriptor& | 4531 IndexedDBBackingStore::Transaction::WriteDescriptor& |
4438 IndexedDBBackingStore::Transaction::WriteDescriptor:: | 4532 IndexedDBBackingStore::Transaction::WriteDescriptor:: |
4439 operator=(const WriteDescriptor& other) = default; | 4533 operator=(const WriteDescriptor& other) = default; |
4440 | 4534 |
4441 } // namespace content | 4535 } // namespace content |
OLD | NEW |