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 if (cursor_options_.forward) | |
3178 return ContinueNext(key, primary_key, next_state, s); | |
3179 else | |
3180 return ContinuePrevious(key, primary_key, next_state, s); | |
3181 } | |
3182 | |
3183 bool IndexedDBBackingStore::Cursor::ContinueNext( | |
3184 const IndexedDBKey* key, | |
3185 const IndexedDBKey* primary_key, | |
3186 IteratorState next_state, | |
3187 leveldb::Status* s) { | |
3188 DCHECK(cursor_options_.forward); | |
3177 DCHECK(!key || key->IsValid()); | 3189 DCHECK(!key || key->IsValid()); |
3178 DCHECK(!primary_key || primary_key->IsValid()); | 3190 DCHECK(!primary_key || primary_key->IsValid()); |
3179 *s = leveldb::Status::OK(); | 3191 *s = leveldb::Status::OK(); |
3180 | 3192 |
3181 // TODO(alecflett): avoid a copy here? | 3193 // TODO(alecflett): avoid a copy here? |
3182 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); | 3194 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); |
3183 | 3195 |
3184 // When iterating with PrevNoDuplicate, spec requires that the | 3196 // 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 | 3197 // skip the cursor forward rather than iterating it. |
3186 // order. | 3198 if (next_state == SEEK && key) { |
jsbell
2015/06/09 18:52:19
It should never be the case that key is specified
jsbell
2015/06/10 17:51:57
Done.
| |
3199 std::string leveldb_key; | |
3200 if (primary_key) | |
jsbell
2015/06/09 18:52:19
Clearer as ternary (?:) operation?
jsbell
2015/06/10 17:51:57
Done.
| |
3201 leveldb_key = EncodeKey(*key, *primary_key); | |
3202 else | |
3203 leveldb_key = EncodeKey(*key); | |
3204 *s = iterator_->Seek(leveldb_key); | |
3205 if (!s->ok()) | |
3206 return false; | |
3207 // Cursor may be at the next value already; don't advance it again below. | |
cmumford
2015/06/09 17:06:24
Is it a maybe, or is it for sure at the next value
jsbell
2015/06/10 17:51:58
Done.
(It may be positioned at a stale entry and
| |
3208 next_state = READY; | |
3209 } | |
3210 | |
3211 for (;;) { | |
3212 // Only advance the cursor if it was not set to position already, | |
3213 // either because it is newly opened (and positioned at start of range) | |
3214 // or skipped forward by continue with a specific key. | |
3215 if (next_state == SEEK) { | |
3216 *s = iterator_->Next(); | |
3217 if (!s->ok()) | |
3218 return false; | |
3219 } else { | |
3220 next_state = SEEK; | |
3221 } | |
3222 | |
3223 // TODO(jsbell): Can we DCHECK iterator_->IsValid() up top? | |
3224 // Fail if we've run out of data or gone past the cursor's bounds. | |
3225 if (!iterator_->IsValid() || IsPastBounds()) | |
3226 return false; | |
3227 | |
3228 // TODO(jsbell): Document why this might be false. When do we ever not | |
3229 // seek into the range before starting cursor iteration? | |
3230 if (!HaveEnteredRange()) | |
3231 continue; | |
3232 | |
3233 // The row may not load because there's a stale entry in the | |
3234 // index. If no error then not fatal. | |
3235 if (!LoadCurrentRow(s)) { | |
3236 if (!s->ok()) | |
3237 return false; | |
3238 continue; | |
3239 } | |
3240 | |
3241 // If seeking to a key (or key and primary key), continue until found. | |
jsbell
2015/06/09 18:52:19
Due to the Seek() optimization above, this block s
jsbell
2015/06/10 17:51:57
Added comment. Will run tests w/ DCHECK and remove
| |
3242 if (key) { | |
3243 if (primary_key && current_key_->Equals(*key) && | |
3244 this->primary_key().IsLessThan(*primary_key)) | |
3245 continue; | |
3246 if (current_key_->IsLessThan(*key)) | |
3247 continue; | |
3248 } | |
3249 | |
jsbell
2015/06/09 18:52:19
Add a comment here:
// Cursor is now positioned a
jsbell
2015/06/10 17:51:57
Done.
| |
3250 // "Unique" cursors should continue seeking until a new key value is seen. | |
3251 if (cursor_options_.unique && previous_key.IsValid() && | |
3252 current_key_->Equals(previous_key)) { | |
3253 continue; | |
3254 } | |
3255 | |
3256 break; | |
3257 } | |
3258 | |
3259 return true; | |
3260 } | |
3261 | |
3262 bool IndexedDBBackingStore::Cursor::ContinuePrevious( | |
3263 const IndexedDBKey* key, | |
3264 const IndexedDBKey* primary_key, | |
3265 IteratorState next_state, | |
3266 leveldb::Status* s) { | |
3267 DCHECK(!cursor_options_.forward); | |
3268 DCHECK(!key || key->IsValid()); | |
3269 DCHECK(!primary_key || primary_key->IsValid()); | |
3270 *s = leveldb::Status::OK(); | |
3271 | |
3272 // TODO(alecflett): avoid a copy here? | |
3273 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); | |
3274 | |
3275 // When iterating with PrevNoDuplicate, spec requires that the value we | |
3276 // yield for each key is the *first* duplicate in forwards order. We do this | |
3277 // by remembering the *last* duplicate seen (implicitly, the first value | |
3278 // seen with a new key), continuing until another new key is seen, then | |
3279 // reversing until we find a key equal to the *last* duplicate. | |
3187 IndexedDBKey last_duplicate_key; | 3280 IndexedDBKey last_duplicate_key; |
3281 bool find_first_duplicate = false; | |
jsbell
2015/06/09 15:47:32
Renamed from "flipped"
| |
3188 | 3282 |
3189 bool forward = cursor_options_.forward; | 3283 // TODO(jsbell): Optimize continuing to a specific key (or key and primary |
3190 bool first_iteration_forward = forward; | 3284 // key) for reverse cursors as well. See Seek() optimization at the start |
3191 bool flipped = false; | 3285 // of ContinueNext() for an example. |
3192 | 3286 |
3193 for (;;) { | 3287 for (;;) { |
3194 if (next_state == SEEK) { | 3288 if (next_state == SEEK) { |
3195 // TODO(jsbell): Optimize seeking for reverse cursors as well. | 3289 *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()) | 3290 if (!s->ok()) |
3211 return false; | 3291 return false; |
3212 } else { | 3292 } else { |
3213 next_state = SEEK; // for subsequent iterations | 3293 next_state = SEEK; // for subsequent iterations |
3214 } | 3294 } |
3215 | 3295 |
3216 if (!iterator_->IsValid()) { | 3296 // If we've run out of data or gone past the cursor's bounds. |
3217 if (!forward && last_duplicate_key.IsValid()) { | 3297 if (!iterator_->IsValid() || IsPastBounds()) { |
3218 // We need to walk forward because we hit the end of | 3298 if (last_duplicate_key.IsValid()) { |
3219 // the data. | 3299 // Walk the cursor forward to the first duplicate. |
3220 forward = true; | 3300 find_first_duplicate = true; |
3221 flipped = true; | 3301 break; |
3222 continue; | |
3223 } | 3302 } |
3224 | 3303 |
3225 return false; | 3304 return false; |
3226 } | 3305 } |
3227 | 3306 |
3228 if (IsPastBounds()) { | 3307 // TODO(jsbell): Document why this might be false. When do we ever not |
3229 if (!forward && last_duplicate_key.IsValid()) { | 3308 // 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()) | 3309 if (!HaveEnteredRange()) |
3241 continue; | 3310 continue; |
3242 | 3311 |
3243 // The row may not load because there's a stale entry in the | 3312 // The row may not load because there's a stale entry in the |
3244 // index. If no error then not fatal. | 3313 // index. If no error then not fatal. |
3245 if (!LoadCurrentRow(s)) { | 3314 if (!LoadCurrentRow(s)) { |
3246 if (!s->ok()) | 3315 if (!s->ok()) |
3247 return false; | 3316 return false; |
3248 continue; | 3317 continue; |
3249 } | 3318 } |
3250 | 3319 |
3320 // If seeking to a key (or key and primary key), continue until found. | |
3251 if (key) { | 3321 if (key) { |
3252 if (forward) { | 3322 if (primary_key && key->Equals(*current_key_) && |
3253 if (primary_key && current_key_->Equals(*key) && | 3323 primary_key->IsLessThan(this->primary_key())) |
3254 this->primary_key().IsLessThan(*primary_key)) | 3324 continue; |
3255 continue; | 3325 if (key->IsLessThan(*current_key_)) |
3256 if (!flipped && current_key_->IsLessThan(*key)) | 3326 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 } | 3327 } |
3266 | 3328 |
jsbell
2015/06/09 18:52:19
Add comment here:
// Cursor is now positioned at
jsbell
2015/06/10 17:51:57
Done.
| |
3267 if (cursor_options_.unique) { | 3329 if (cursor_options_.unique) { |
3268 if (previous_key.IsValid() && current_key_->Equals(previous_key)) { | 3330 if (previous_key.IsValid() && current_key_->Equals(previous_key)) { |
3269 // We should never be able to walk forward all the way | 3331 // We should never be able to walk forward all the way |
jsbell
2015/06/09 18:52:19
This comment/DCHECK no longer make sense since dir
jsbell
2015/06/10 17:51:57
Done.
| |
3270 // to the previous key. | 3332 // to the previous key. |
3271 DCHECK(!last_duplicate_key.IsValid()); | 3333 DCHECK(!last_duplicate_key.IsValid()); |
3272 continue; | 3334 continue; |
3273 } | 3335 } |
3274 | 3336 |
3275 if (!forward) { | 3337 // If we've found a new key, remember it and keep going. |
3276 if (!last_duplicate_key.IsValid()) { | 3338 if (!last_duplicate_key.IsValid()) { |
3277 last_duplicate_key = *current_key_; | 3339 last_duplicate_key = *current_key_; |
3278 continue; | |
3279 } | |
3280 | |
3281 // We need to walk forward because we hit the boundary | |
3282 // between key ranges. | |
3283 if (!last_duplicate_key.Equals(*current_key_)) { | |
3284 forward = true; | |
3285 flipped = true; | |
3286 continue; | |
3287 } | |
3288 | |
3289 continue; | 3340 continue; |
3290 } | 3341 } |
3342 | |
3343 // If we're still seeing duplicates, keep going. | |
3344 if (last_duplicate_key.Equals(*current_key_)) | |
3345 continue; | |
3346 | |
3347 // Walk the cursor forward to the first duplicate. | |
3348 find_first_duplicate = true; | |
3291 } | 3349 } |
3350 | |
3292 break; | 3351 break; |
3293 } | 3352 } |
3294 | 3353 |
3354 // TODO(jsbell): Rather than iterating, stash the last leveldb key of the | |
3355 // last plausible result, then Seek() the cursor directly to that and | |
3356 // LoadCurrentRow(). | |
3357 | |
3358 if (find_first_duplicate) { | |
3359 DCHECK_EQ(next_state, SEEK); | |
3360 DCHECK(cursor_options_.unique); | |
3361 for (;;) { | |
3362 *s = iterator_->Next(); | |
3363 if (!s->ok()) | |
cmumford
2015/06/09 17:06:24
What about:
if (!s->ok() || !iterator_->IsValid()
jsbell
2015/06/10 17:51:57
Done.
| |
3364 return false; | |
3365 | |
3366 if (!iterator_->IsValid() || IsPastBounds()) | |
3367 return false; | |
3368 | |
3369 // TODO(jsbell): Document why this might be false. When do we ever not | |
3370 // seek into the range before starting cursor iteration? | |
3371 if (!HaveEnteredRange()) | |
3372 continue; | |
3373 | |
3374 // The row may not load because there's a stale entry in the | |
3375 // index. If no error then not fatal. | |
3376 if (!LoadCurrentRow(s)) { | |
3377 if (!s->ok()) | |
3378 return false; | |
3379 continue; | |
3380 } | |
3381 | |
jsbell
2015/06/09 15:47:32
I removed two clauses here from when we were pairi
| |
3382 break; | |
3383 } | |
3384 } | |
3385 | |
3295 DCHECK(!last_duplicate_key.IsValid() || | 3386 DCHECK(!last_duplicate_key.IsValid() || |
3296 (forward && last_duplicate_key.Equals(*current_key_))); | 3387 (find_first_duplicate && last_duplicate_key.Equals(*current_key_))); |
3297 return true; | 3388 return true; |
3298 } | 3389 } |
3299 | 3390 |
3300 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { | 3391 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { |
3301 if (cursor_options_.forward) { | 3392 if (cursor_options_.forward) { |
3302 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); | 3393 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); |
3303 if (cursor_options_.low_open) { | 3394 if (cursor_options_.low_open) { |
3304 return compare > 0; | 3395 return compare > 0; |
3305 } | 3396 } |
3306 return compare >= 0; | 3397 return compare >= 0; |
(...skipping 1125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4432 | 4523 |
4433 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | 4524 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
4434 const WriteDescriptor& other) = default; | 4525 const WriteDescriptor& other) = default; |
4435 IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() = | 4526 IndexedDBBackingStore::Transaction::WriteDescriptor::~WriteDescriptor() = |
4436 default; | 4527 default; |
4437 IndexedDBBackingStore::Transaction::WriteDescriptor& | 4528 IndexedDBBackingStore::Transaction::WriteDescriptor& |
4438 IndexedDBBackingStore::Transaction::WriteDescriptor:: | 4529 IndexedDBBackingStore::Transaction::WriteDescriptor:: |
4439 operator=(const WriteDescriptor& other) = default; | 4530 operator=(const WriteDescriptor& other) = default; |
4440 | 4531 |
4441 } // namespace content | 4532 } // namespace content |
OLD | NEW |