/* * 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 "FDBTypes.h" #include "boost/range.hpp" #include "flow/IndexedSet.h" #include "SystemData.h" #include "fdbrpc/RangeMap.h" #include "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(true) { 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(true) { 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(true) { 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< KeyRange >& 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< Future > 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 ); Standalone krmDecodeRanges( KeyRef mapPrefix, KeyRange keys, Standalone 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