| 624 | } |
| 625 | |
| 626 | Key findKey(StorageCacheData* data, KeySelectorRef sel, Version version, KeyRange range, int* pOffset) |
| 627 | // Attempts to find the key indicated by sel in the data at version, within range. |
| 628 | // Precondition: selectorInRange(sel, range) |
| 629 | // If it is found, offset is set to 0 and a key is returned which falls inside range. |
| 630 | // If the search would depend on any key outside range OR if the key selector offset is too large (range read returns |
| 631 | // too many bytes), it returns either |
| 632 | // a negative offset and a key in [range.begin, sel.getKey()], indicating the key is (the first key <= returned key) + |
| 633 | // offset, or a positive offset and a key in (sel.getKey(), range.end], indicating the key is (the first key >= |
| 634 | // returned key) + offset-1 |
| 635 | // The range passed in to this function should specify a cacheRange. If range.begin is repeatedly not the beginning of |
| 636 | // a cacheRange, then it is possible to get stuck looping here |
| 637 | { |
| 638 | ASSERT(version != latestVersion); |
| 639 | ASSERT(selectorInRange(sel, range) && version >= data->oldestVersion.get()); |
| 640 | |
| 641 | // Count forward or backward distance items, skipping the first one if it == key and skipEqualKey |
| 642 | bool forward = sel.offset > 0; // If forward, result >= sel.getKey(); else result <= sel.getKey() |
| 643 | int sign = forward ? +1 : -1; |
| 644 | bool skipEqualKey = sel.orEqual == forward; |
| 645 | int distance = forward ? sel.offset : 1 - sel.offset; |
| 646 | |
| 647 | // Don't limit the number of bytes if this is a trivial key selector (there will be at most two items returned from |
| 648 | // the read range in this case) |
| 649 | int maxBytes; |
| 650 | if (sel.offset <= 1 && sel.offset >= 0) |
| 651 | maxBytes = std::numeric_limits<int>::max(); |
| 652 | else |
| 653 | maxBytes = BUGGIFY ? SERVER_KNOBS->BUGGIFY_LIMIT_BYTES : SERVER_KNOBS->STORAGE_LIMIT_BYTES; |
| 654 | |
| 655 | GetKeyValuesReply rep = |
| 656 | readRange(data, |
| 657 | version, |
| 658 | forward ? KeyRangeRef(sel.getKey(), range.end) : KeyRangeRef(range.begin, keyAfter(sel.getKey())), |
| 659 | (distance + skipEqualKey) * sign, |
| 660 | &maxBytes); |
| 661 | bool more = rep.more && rep.data.size() != distance + skipEqualKey; |
| 662 | |
| 663 | // If we get only one result in the reverse direction as a result of the data being too large, we could get stuck in |
| 664 | // a loop |
| 665 | if (more && !forward && rep.data.size() == 1) { |
| 666 | CODE_PROBE(true, "Reverse key selector returned only one result in range read"); |
| 667 | maxBytes = std::numeric_limits<int>::max(); |
| 668 | GetKeyValuesReply rep2 = |
| 669 | readRange(data, version, KeyRangeRef(range.begin, keyAfter(sel.getKey())), -2, &maxBytes); |
| 670 | rep = rep2; |
| 671 | more = rep.more && rep.data.size() != distance + skipEqualKey; |
| 672 | ASSERT(rep.data.size() == 2 || !more); |
| 673 | } |
| 674 | |
| 675 | int index = distance - 1; |
| 676 | if (skipEqualKey && rep.data.size() && rep.data[0].key == sel.getKey()) |
| 677 | ++index; |
| 678 | |
| 679 | if (index < rep.data.size()) { |
| 680 | *pOffset = 0; |
| 681 | return rep.data[index].key; |
| 682 | } else { |
| 683 | // FIXME: If range.begin=="" && !forward, return success? |
no test coverage detected