322 lines
13 KiB
C++
322 lines
13 KiB
C++
/*
|
|
* 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 Val, class Metric=int, class MetricFunc = ConstantMetric<Metric>>
|
|
class KeyRangeMap : public RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>, NonCopyable, public ReferenceCounted<KeyRangeMap<Val>> {
|
|
public:
|
|
explicit KeyRangeMap(Val v=Val(), Key endKey = allKeys.end) : RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>(endKey, v), mapEnd(endKey) {}
|
|
void operator=(KeyRangeMap&& r) noexcept(true) { mapEnd = std::move(r.mapEnd); RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::operator=(std::move(r)); }
|
|
void insert( const KeyRangeRef& keys, const Val& value ) { RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::insert(keys, value); }
|
|
void insert( const KeyRef& key, const Val& value ) { RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::insert( singleKeyRange(key), value); }
|
|
std::vector<KeyRangeWith<Val>> getAffectedRangesAfterInsertion( const KeyRangeRef& keys, const Val &insertionValue = Val());
|
|
typename RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::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<Key,Val> valueBeforeRange(keys.begin, RangeMap<Key,Val,KeyRangeRef,Metric>::rangeContaining(keys.begin).value());
|
|
MapPair<Key,Val> valueAfterRange(keys.end, RangeMap<Key,Val,KeyRangeRef,Metric>::rangeContaining(keys.end).value());
|
|
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(std::move(valueBeforeRange));
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(std::move(valueAfterRange));
|
|
return RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::intersectingRanges( keys );
|
|
}
|
|
|
|
void rawErase( KeyRange const& range ) {
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.erase(RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.lower_bound(range.begin), RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.lower_bound(range.end));
|
|
}
|
|
void rawInsert( Key const& key, Val const& value ) {
|
|
MapPair<Key,Val> pair(key, value);
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(pair, true, RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::mf(pair));
|
|
}
|
|
void rawInsert( const std::vector<std::pair<MapPair<Key,Val>, Metric>>& pairs ) {
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(pairs);
|
|
}
|
|
Key mapEnd;
|
|
};
|
|
|
|
template <class Val, class Metric=int, class MetricFunc = ConstantMetric<Metric>>
|
|
class CoalescedKeyRefRangeMap : public RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>, NonCopyable {
|
|
public:
|
|
explicit CoalescedKeyRefRangeMap(Val v=Val(), Key endKey = allKeys.end) : RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>(endKey, v), mapEnd(endKey) {}
|
|
void operator=(CoalescedKeyRefRangeMap&& r) noexcept(true) { mapEnd = std::move(r.mapEnd); RangeMap<KeyRef, Val, KeyRangeRef,Metric,MetricFunc>::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 Val, class Metric=int, class MetricFunc = ConstantMetric<Metric>>
|
|
class CoalescedKeyRangeMap : public RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>, NonCopyable {
|
|
public:
|
|
explicit CoalescedKeyRangeMap(Val v=Val(), Key endKey = allKeys.end) : RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>(endKey, v), mapEnd(endKey) {}
|
|
void operator=(CoalescedKeyRangeMap&& r) noexcept(true) { mapEnd = std::move(r.mapEnd); RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::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<Void>& value ) { map.insert( keys, value ); }
|
|
void cancel( const KeyRangeRef& keys ) { insert( keys, Future<Void>() ); }
|
|
bool liveActorAt( const KeyRef& key ) { Future<Void> actorAt = map[key]; return actorAt.isValid() && !actorAt.isReady(); }
|
|
private:
|
|
KeyRangeMap< Future<Void> > map;
|
|
};
|
|
|
|
// krm*(): KeyRangeMap-like abstraction stored in the database, accessed through Transactions
|
|
class Transaction;
|
|
class ReadYourWritesTransaction;
|
|
Future<Standalone<RangeResultRef>> 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<Standalone<RangeResultRef>> krmGetRanges( Reference<ReadYourWritesTransaction> 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<Void> krmSetRange( Transaction* const& tr, Key const& mapPrefix, KeyRange const& range, Value const& value );
|
|
Future<Void> krmSetRange( Reference<ReadYourWritesTransaction> const& tr, Key const& mapPrefix, KeyRange const& range, Value const& value );
|
|
Future<Void> krmSetRangeCoalescing( Transaction* const& tr, Key const& mapPrefix, KeyRange const& range, KeyRange const& maxRange, Value const& value );
|
|
Standalone<RangeResultRef> krmDecodeRanges( KeyRef mapPrefix, KeyRange keys, Standalone<RangeResultRef> kv );
|
|
|
|
template <class Val, class Metric, class MetricFunc>
|
|
std::vector<KeyRangeWith<Val>> KeyRangeMap<Val,Metric,MetricFunc>::getAffectedRangesAfterInsertion( const KeyRangeRef& keys, const Val &insertionValue) {
|
|
std::vector<KeyRangeWith<Val>> affectedRanges;
|
|
|
|
{ // possible first range if no exact alignment
|
|
auto r = RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::rangeContaining( keys.begin );
|
|
if (r->begin() != keys.begin)
|
|
affectedRanges.push_back(
|
|
KeyRangeWith<Val>(
|
|
KeyRangeRef(r->begin(), keys.begin), r->value() ) );
|
|
}
|
|
|
|
affectedRanges.push_back( KeyRangeWith<Val>( keys, insertionValue) );
|
|
|
|
{ // possible last range if no exact alignment
|
|
auto r = RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::rangeContaining( keys.end );
|
|
if (r->begin() != keys.end)
|
|
affectedRanges.push_back(
|
|
KeyRangeWith<Val>(
|
|
KeyRangeRef(keys.end, r->end()), r->value() ) );
|
|
}
|
|
|
|
return affectedRanges;
|
|
}
|
|
|
|
template <class Val, class Metric, class MetricFunc>
|
|
void CoalescedKeyRangeMap<Val,Metric,MetricFunc>::insert( const KeyRangeRef& keys, const Val& value ) {
|
|
ASSERT(keys.end <= mapEnd);
|
|
|
|
if( keys.empty() )
|
|
return;
|
|
|
|
auto begin = RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.lower_bound( keys.begin );
|
|
auto end = RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::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<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.erase(begin, end);
|
|
if(insertEnd) {
|
|
MapPair<Key,Val> p(keys.end, endVal);
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
if(insertBegin) {
|
|
MapPair<Key,Val> p(keys.begin, value);
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
}
|
|
|
|
template <class Val, class Metric, class MetricFunc>
|
|
void CoalescedKeyRangeMap<Val,Metric,MetricFunc>::insert( const KeyRef& key, const Val& value ) {
|
|
ASSERT(key < mapEnd);
|
|
|
|
auto begin = RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::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<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.erase(begin, end);
|
|
if(insertEnd) {
|
|
MapPair<Key,Val> p(keyAfter(key), endVal);
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
if(insertBegin) {
|
|
MapPair<Key,Val> p(key, value);
|
|
RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<Key,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
}
|
|
|
|
template <class Val, class Metric, class MetricFunc>
|
|
void CoalescedKeyRefRangeMap<Val,Metric,MetricFunc>::insert( const KeyRangeRef& keys, const Val& value ) {
|
|
ASSERT(keys.end <= mapEnd);
|
|
|
|
if( keys.empty() )
|
|
return;
|
|
|
|
auto begin = RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.lower_bound( keys.begin );
|
|
auto end = RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::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<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.erase(begin, end);
|
|
if(insertEnd) {
|
|
MapPair<KeyRef,Val> p(keys.end, endVal);
|
|
RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
if(insertBegin) {
|
|
MapPair<KeyRef,Val> p(keys.begin, value);
|
|
RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
}
|
|
|
|
template <class Val, class Metric, class MetricFunc>
|
|
void CoalescedKeyRefRangeMap<Val,Metric,MetricFunc>::insert( const KeyRef& key, const Val& value, Arena& arena ) {
|
|
ASSERT(key < mapEnd);
|
|
|
|
auto begin = RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::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<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.erase(begin, end);
|
|
if(insertEnd) {
|
|
MapPair<KeyRef,Val> p(keyAfter(key, arena), endVal);
|
|
RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
if(insertBegin) {
|
|
MapPair<KeyRef,Val> p(key,value);
|
|
RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::map.insert(p, true, RangeMap<KeyRef,Val,KeyRangeRef,Metric,MetricFunc>::mf(p));
|
|
}
|
|
}
|
|
|
|
#endif
|