/* * KeyRangeMap.h * * This source file is part of the FoundationDB open source project * * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FLOW_KEYRANGEMAP_H #define FLOW_KEYRANGEMAP_H #pragma once #include "flow/flow.h" #include "fdbclient/FDBTypes.h" #include "boost/range.hpp" #include "flow/IndexedSet.h" #include "fdbclient/SystemData.h" #include "fdbrpc/RangeMap.h" #include "fdbclient/Knobs.h" using boost::iterator_range; template > class KeyRangeMap : public RangeMap, NonCopyable, public ReferenceCounted> { public: explicit KeyRangeMap(Val v = Val(), Key endKey = allKeys.end) : RangeMap(endKey, v), mapEnd(endKey) {} void operator=(KeyRangeMap&& r) noexcept { mapEnd = std::move(r.mapEnd); RangeMap::operator=(std::move(r)); } void insert(const KeyRangeRef& keys, const Val& value) { RangeMap::insert(keys, value); } void insert(const KeyRef& key, const Val& value) { RangeMap::insert(singleKeyRange(key), value); } std::vector> getAffectedRangesAfterInsertion(const KeyRangeRef& keys, const Val& insertionValue = Val()); typename RangeMap::Ranges modify( const KeyRangeRef& keys) // Returns ranges, the first of which begins at keys.begin and the last of which ends at keys.end { MapPair valueBeforeRange( keys.begin, RangeMap::rangeContaining(keys.begin).value()); MapPair valueAfterRange(keys.end, RangeMap::rangeContaining(keys.end).value()); RangeMap::map.insert(std::move(valueBeforeRange)); RangeMap::map.insert(std::move(valueAfterRange)); return RangeMap::intersectingRanges(keys); } void rawErase(KeyRange const& range) { RangeMap::map.erase( RangeMap::map.lower_bound(range.begin), RangeMap::map.lower_bound(range.end)); } void rawInsert(Key const& key, Val const& value) { MapPair pair(key, value); RangeMap::map.insert( pair, true, RangeMap::mf(pair)); } void rawInsert(const std::vector, Metric>>& pairs) { RangeMap::map.insert(pairs); } Key mapEnd; }; template > class CoalescedKeyRefRangeMap : public RangeMap, NonCopyable { public: explicit CoalescedKeyRefRangeMap(Val v = Val(), Key endKey = allKeys.end) : RangeMap(endKey, v), mapEnd(endKey) {} void operator=(CoalescedKeyRefRangeMap&& r) noexcept { mapEnd = std::move(r.mapEnd); RangeMap::operator=(std::move(r)); } void insert(const KeyRangeRef& keys, const Val& value); void insert(const KeyRef& key, const Val& value, Arena& arena); Key mapEnd; }; template > class CoalescedKeyRangeMap : public RangeMap, NonCopyable { public: explicit CoalescedKeyRangeMap(Val v = Val(), Key endKey = allKeys.end) : RangeMap(endKey, v), mapEnd(endKey) {} void operator=(CoalescedKeyRangeMap&& r) noexcept { mapEnd = std::move(r.mapEnd); RangeMap::operator=(std::move(r)); } void insert(const KeyRangeRef& keys, const Val& value); void insert(const KeyRef& key, const Val& value); Key mapEnd; }; class KeyRangeActorMap { public: void getRangesAffectedByInsertion(const KeyRangeRef& keys, vector& affectedRanges); void insert(const KeyRangeRef& keys, const Future& value) { map.insert(keys, value); } void cancel(const KeyRangeRef& keys) { insert(keys, Future()); } bool liveActorAt(const KeyRef& key) { Future actorAt = map[key]; return actorAt.isValid() && !actorAt.isReady(); } private: KeyRangeMap> map; }; // krm*(): KeyRangeMap-like abstraction stored in the database, accessed through Transactions class Transaction; class ReadYourWritesTransaction; Future krmGetRanges(Transaction* const& tr, Key const& mapPrefix, KeyRange const& keys, int const& limit = CLIENT_KNOBS->KRM_GET_RANGE_LIMIT, int const& limitBytes = CLIENT_KNOBS->KRM_GET_RANGE_LIMIT_BYTES); Future krmGetRanges(Reference const& tr, Key const& mapPrefix, KeyRange const& keys, int const& limit = CLIENT_KNOBS->KRM_GET_RANGE_LIMIT, int const& limitBytes = CLIENT_KNOBS->KRM_GET_RANGE_LIMIT_BYTES); void krmSetPreviouslyEmptyRange(Transaction* tr, const KeyRef& mapPrefix, const KeyRangeRef& keys, const ValueRef& newValue, const ValueRef& oldEndValue); void krmSetPreviouslyEmptyRange(struct CommitTransactionRef& tr, Arena& trArena, const KeyRef& mapPrefix, const KeyRangeRef& keys, const ValueRef& newValue, const ValueRef& oldEndValue); Future krmSetRange(Transaction* const& tr, Key const& mapPrefix, KeyRange const& range, Value const& value); Future krmSetRange(Reference const& tr, Key const& mapPrefix, KeyRange const& range, Value const& value); Future krmSetRangeCoalescing(Transaction* const& tr, Key const& mapPrefix, KeyRange const& range, KeyRange const& maxRange, Value const& value); Future krmSetRangeCoalescing(Reference const& tr, Key const& mapPrefix, KeyRange const& range, KeyRange const& maxRange, Value const& value); RangeResult krmDecodeRanges(KeyRef mapPrefix, KeyRange keys, RangeResult kv); template std::vector> KeyRangeMap::getAffectedRangesAfterInsertion( const KeyRangeRef& keys, const Val& insertionValue) { std::vector> affectedRanges; { // possible first range if no exact alignment auto r = RangeMap::rangeContaining(keys.begin); if (r->begin() != keys.begin) affectedRanges.push_back(KeyRangeWith(KeyRangeRef(r->begin(), keys.begin), r->value())); } affectedRanges.push_back(KeyRangeWith(keys, insertionValue)); { // possible last range if no exact alignment auto r = RangeMap::rangeContaining(keys.end); if (r->begin() != keys.end) affectedRanges.push_back(KeyRangeWith(KeyRangeRef(keys.end, r->end()), r->value())); } return affectedRanges; } template void CoalescedKeyRangeMap::insert(const KeyRangeRef& keys, const Val& value) { ASSERT(keys.end <= mapEnd); if (keys.empty()) return; auto begin = RangeMap::map.lower_bound(keys.begin); auto end = RangeMap::map.lower_bound(keys.end); bool insertEnd = false; bool insertBegin = false; Val endVal; if (keys.end != mapEnd) { if (end->key != keys.end) { auto before_end = end; before_end.decrementNonEnd(); if (value != before_end->value) { insertEnd = true; endVal = before_end->value; } } if (!insertEnd && end->value == value && end->key != mapEnd) { ++end; } } if (keys.begin == allKeys.begin) { insertBegin = true; } else { auto before_begin = begin; before_begin.decrementNonEnd(); if (before_begin->value != value) insertBegin = true; } RangeMap::map.erase(begin, end); if (insertEnd) { MapPair p(keys.end, endVal); RangeMap::map.insert( p, true, RangeMap::mf(p)); } if (insertBegin) { MapPair p(keys.begin, value); RangeMap::map.insert( p, true, RangeMap::mf(p)); } } template void CoalescedKeyRangeMap::insert(const KeyRef& key, const Val& value) { ASSERT(key < mapEnd); auto begin = RangeMap::map.lower_bound(key); auto end = begin; if (end->key == key) ++end; bool insertEnd = false; bool insertBegin = false; Val endVal; if (!equalsKeyAfter(key, end->key)) { auto before_end = end; before_end.decrementNonEnd(); if (value != before_end->value) { insertEnd = true; endVal = before_end->value; } } if (!insertEnd && end->value == value && end->key != mapEnd) { ++end; } if (key == allKeys.begin) { insertBegin = true; } else { auto before_begin = begin; before_begin.decrementNonEnd(); if (before_begin->value != value) insertBegin = true; } RangeMap::map.erase(begin, end); if (insertEnd) { MapPair p(keyAfter(key), endVal); RangeMap::map.insert( p, true, RangeMap::mf(p)); } if (insertBegin) { MapPair p(key, value); RangeMap::map.insert( p, true, RangeMap::mf(p)); } } template void CoalescedKeyRefRangeMap::insert(const KeyRangeRef& keys, const Val& value) { ASSERT(keys.end <= mapEnd); if (keys.empty()) return; auto begin = RangeMap::map.lower_bound(keys.begin); auto end = RangeMap::map.lower_bound(keys.end); bool insertEnd = false; bool insertBegin = false; Val endVal; if (keys.end != mapEnd) { if (end->key != keys.end) { auto before_end = end; before_end.decrementNonEnd(); if (value != before_end->value) { insertEnd = true; endVal = before_end->value; } } if (!insertEnd && end->value == value && end->key != mapEnd) { ++end; } } if (keys.begin == allKeys.begin) { insertBegin = true; } else { auto before_begin = begin; before_begin.decrementNonEnd(); if (before_begin->value != value) insertBegin = true; } RangeMap::map.erase(begin, end); if (insertEnd) { MapPair p(keys.end, endVal); RangeMap::map.insert( p, true, RangeMap::mf(p)); } if (insertBegin) { MapPair p(keys.begin, value); RangeMap::map.insert( p, true, RangeMap::mf(p)); } } template void CoalescedKeyRefRangeMap::insert(const KeyRef& key, const Val& value, Arena& arena) { ASSERT(key < mapEnd); auto begin = RangeMap::map.lower_bound(key); auto end = begin; if (end->key == key) ++end; bool insertEnd = false; bool insertBegin = false; Val endVal; if (!equalsKeyAfter(key, end->key)) { auto before_end = end; before_end.decrementNonEnd(); if (value != before_end->value) { insertEnd = true; endVal = before_end->value; } } if (!insertEnd && end->value == value && end->key != mapEnd) { ++end; } if (key == allKeys.begin) { insertBegin = true; } else { auto before_begin = begin; before_begin.decrementNonEnd(); if (before_begin->value != value) insertBegin = true; } RangeMap::map.erase(begin, end); if (insertEnd) { MapPair p(keyAfter(key, arena), endVal); RangeMap::map.insert( p, true, RangeMap::mf(p)); } if (insertBegin) { MapPair p(key, value); RangeMap::map.insert( p, true, RangeMap::mf(p)); } } #endif