2017-05-26 04:48:44 +08:00
/*
2019-03-06 02:29:37 +08:00
* DataDistribution . actor . h
2017-05-26 04:48:44 +08:00
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013 - 2018 Apple Inc . and the FoundationDB project authors
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* 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
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* http : //www.apache.org/licenses/LICENSE-2.0
2018-02-22 02:25:11 +08:00
*
2017-05-26 04:48:44 +08:00
* 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 .
*/
2019-03-06 02:29:37 +08:00
# if defined(NO_INTELLISENSE) && !defined(FDBSERVER_DATA_DISTRIBUTION_ACTOR_G_H)
# define FDBSERVER_DATA_DISTRIBUTION_ACTOR_G_H
# include "fdbserver/DataDistribution.actor.g.h"
# elif !defined(FDBSERVER_DATA_DISTRIBUTION_ACTOR_H)
# define FDBSERVER_DATA_DISTRIBUTION_ACTOR_H
2019-02-18 07:41:16 +08:00
# include "fdbclient/NativeAPI.actor.h"
2019-02-18 10:55:52 +08:00
# include "fdbserver/MoveKeys.actor.h"
2018-10-20 01:30:13 +08:00
# include "fdbserver/LogSystem.h"
2019-03-06 02:29:37 +08:00
# include "flow/actorcompiler.h" // This must be the last #include.
2017-05-26 04:48:44 +08:00
struct RelocateShard {
KeyRange keys ;
int priority ;
2018-04-09 12:24:05 +08:00
RelocateShard ( ) : priority ( 0 ) { }
2017-05-26 04:48:44 +08:00
RelocateShard ( KeyRange const & keys , int priority ) : keys ( keys ) , priority ( priority ) { }
} ;
struct IDataDistributionTeam {
2020-07-21 15:08:01 +08:00
virtual vector < StorageServerInterface > getLastKnownServerInterfaces ( ) const = 0 ;
virtual int size ( ) const = 0 ;
virtual vector < UID > const & getServerIDs ( ) const = 0 ;
2017-05-26 04:48:44 +08:00
virtual void addDataInFlightToTeam ( int64_t delta ) = 0 ;
2020-07-21 15:08:01 +08:00
virtual int64_t getDataInFlightToTeam ( ) const = 0 ;
virtual int64_t getLoadBytes ( bool includeInFlight = true , double inflightPenalty = 1.0 ) const = 0 ;
virtual int64_t getMinAvailableSpace ( bool includeInFlight = true ) const = 0 ;
virtual double getMinAvailableSpaceRatio ( bool includeInFlight = true ) const = 0 ;
virtual bool hasHealthyAvailableSpace ( double minRatio ) const = 0 ;
2019-07-26 07:27:32 +08:00
virtual Future < Void > updateStorageMetrics ( ) = 0 ;
2017-05-26 04:48:44 +08:00
virtual void addref ( ) = 0 ;
virtual void delref ( ) = 0 ;
2020-07-21 15:08:01 +08:00
virtual bool isHealthy ( ) const = 0 ;
2017-05-26 04:48:44 +08:00
virtual void setHealthy ( bool ) = 0 ;
2020-07-21 15:08:01 +08:00
virtual int getPriority ( ) const = 0 ;
2017-05-26 04:48:44 +08:00
virtual void setPriority ( int ) = 0 ;
2020-07-21 15:08:01 +08:00
virtual bool isOptimal ( ) const = 0 ;
virtual bool isWrongConfiguration ( ) const = 0 ;
2017-05-26 04:48:44 +08:00
virtual void setWrongConfiguration ( bool ) = 0 ;
2017-10-11 01:36:33 +08:00
virtual void addServers ( const vector < UID > & servers ) = 0 ;
2020-11-17 06:46:36 +08:00
virtual std : : string getTeamID ( ) const = 0 ;
2017-05-26 04:48:44 +08:00
2020-07-21 15:08:01 +08:00
std : : string getDesc ( ) const {
2017-05-26 04:48:44 +08:00
const auto & servers = getLastKnownServerInterfaces ( ) ;
2020-10-24 01:06:22 +08:00
std : : string s = format ( " TeamID:%s " , getTeamID ( ) . c_str ( ) ) ;
2020-10-22 02:10:14 +08:00
s + = format ( " Size %d; " , servers . size ( ) ) ;
2017-05-26 04:48:44 +08:00
for ( int i = 0 ; i < servers . size ( ) ; i + + ) {
if ( i ) s + = " , " ;
s + = servers [ i ] . address ( ) . toString ( ) + " " + servers [ i ] . id ( ) . shortString ( ) ;
}
return s ;
}
} ;
struct GetTeamRequest {
bool wantsNewServers ;
bool wantsTrueBest ;
bool preferLowerUtilization ;
2020-02-21 02:59:52 +08:00
bool teamMustHaveShards ;
2017-05-26 04:48:44 +08:00
double inflightPenalty ;
2018-02-03 03:46:04 +08:00
std : : vector < UID > completeSources ;
2020-06-30 01:02:27 +08:00
std : : vector < UID > src ;
Promise < std : : pair < Optional < Reference < IDataDistributionTeam > > , bool > > reply ;
2017-05-26 04:48:44 +08:00
GetTeamRequest ( ) { }
2020-02-22 07:14:32 +08:00
GetTeamRequest ( bool wantsNewServers , bool wantsTrueBest , bool preferLowerUtilization , bool teamMustHaveShards , double inflightPenalty = 1.0 )
: wantsNewServers ( wantsNewServers ) , wantsTrueBest ( wantsTrueBest ) , preferLowerUtilization ( preferLowerUtilization ) , teamMustHaveShards ( teamMustHaveShards ) , inflightPenalty ( inflightPenalty ) { }
2020-12-27 07:37:54 +08:00
std : : string getDesc ( ) const {
2019-09-08 11:05:59 +08:00
std : : stringstream ss ;
2019-09-12 02:16:29 +08:00
ss < < " WantsNewServers: " < < wantsNewServers < < " WantsTrueBest: " < < wantsTrueBest
2020-02-22 11:09:16 +08:00
< < " PreferLowerUtilization: " < < preferLowerUtilization
< < " teamMustHaveShards: " < < teamMustHaveShards
< < " inflightPenalty: " < < inflightPenalty < < " ; " ;
2019-09-08 11:05:59 +08:00
ss < < " CompleteSources: " ;
2020-12-27 07:37:54 +08:00
for ( const auto & cs : completeSources ) {
2019-09-08 11:05:59 +08:00
ss < < cs . toString ( ) < < " , " ;
}
2020-12-27 07:37:54 +08:00
return std : : move ( ss ) . str ( ) ;
2019-09-08 11:05:59 +08:00
}
2017-05-26 04:48:44 +08:00
} ;
struct GetMetricsRequest {
KeyRange keys ;
Promise < StorageMetrics > reply ;
GetMetricsRequest ( ) { }
GetMetricsRequest ( KeyRange const & keys ) : keys ( keys ) { }
} ;
2019-05-17 07:46:33 +08:00
struct GetMetricsListRequest {
KeyRange keys ;
2019-05-18 07:11:50 +08:00
int shardLimit ;
2020-05-09 08:17:27 +08:00
Promise < Standalone < VectorRef < DDMetricsRef > > > reply ;
2019-05-17 07:46:33 +08:00
GetMetricsListRequest ( ) { }
2019-05-18 07:11:50 +08:00
GetMetricsListRequest ( KeyRange const & keys , const int shardLimit ) : keys ( keys ) , shardLimit ( shardLimit ) { }
2019-05-17 07:46:33 +08:00
} ;
2017-05-26 04:48:44 +08:00
struct TeamCollectionInterface {
PromiseStream < GetTeamRequest > getTeam ;
} ;
class ShardsAffectedByTeamFailure : public ReferenceCounted < ShardsAffectedByTeamFailure > {
public :
ShardsAffectedByTeamFailure ( ) { }
2019-07-10 07:09:51 +08:00
2018-03-09 02:50:05 +08:00
struct Team {
vector < UID > servers ; // sorted
bool primary ;
Team ( ) : primary ( true ) { }
Team ( vector < UID > const & servers , bool primary ) : servers ( servers ) , primary ( primary ) { }
bool operator < ( const Team & r ) const {
if ( servers = = r . servers ) return primary < r . primary ;
2019-07-10 07:09:51 +08:00
return servers < r . servers ;
2018-03-09 02:50:05 +08:00
}
2020-07-11 05:37:47 +08:00
bool operator > ( const Team & r ) const { return r < * this ; }
bool operator < = ( const Team & r ) const { return ! ( * this > r ) ; }
bool operator > = ( const Team & r ) const { return ! ( * this < r ) ; }
2018-03-09 02:50:05 +08:00
bool operator = = ( const Team & r ) const {
return servers = = r . servers & & primary = = r . primary ;
}
2020-07-11 05:37:47 +08:00
bool operator ! = ( const Team & r ) const { return ! ( * this = = r ) ; }
2018-03-09 02:50:05 +08:00
} ;
2017-05-26 04:48:44 +08:00
// This tracks the data distribution on the data distribution server so that teamTrackers can
// relocate the right shards when a team is degraded.
// The following are important to make sure that failure responses don't revert splits or merges:
// - The shards boundaries in the two data structures reflect "queued" RelocateShard requests
// (i.e. reflects the desired set of shards being tracked by dataDistributionTracker,
// rather than the status quo). These boundaries are modified in defineShard and the content
// of what servers correspond to each shard is a copy or union of the shards already there
// - The teams associated with each shard reflect either the sources for non-moving shards
// or the destination team for in-flight shards (the change is atomic with respect to team selection).
// moveShard() changes the servers associated with a shard and will never adjust the shard
// boundaries. If a move is received for a shard that has been redefined (the exact shard is
// no longer in the map), the servers will be set for all contained shards and added to all
// intersecting shards.
2020-12-27 07:37:54 +08:00
int getNumberOfShards ( UID ssID ) const ;
2017-05-26 04:48:44 +08:00
vector < KeyRange > getShardsFor ( Team team ) ;
2020-12-27 07:37:54 +08:00
bool hasShards ( Team team ) const ;
2018-11-13 10:42:29 +08:00
//The first element of the pair is either the source for non-moving shards or the destination team for in-flight shards
//The second element of the pair is all previous sources for in-flight shards
2018-11-12 04:33:31 +08:00
std : : pair < vector < Team > , vector < Team > > getTeamsFor ( KeyRangeRef keys ) ;
2018-11-13 10:42:29 +08:00
2017-05-26 04:48:44 +08:00
void defineShard ( KeyRangeRef keys ) ;
2018-03-09 02:50:05 +08:00
void moveShard ( KeyRangeRef keys , std : : vector < Team > destinationTeam ) ;
2018-11-12 04:33:31 +08:00
void finishMove ( KeyRangeRef keys ) ;
2017-05-26 04:48:44 +08:00
void check ( ) ;
2019-08-06 02:30:22 +08:00
void eraseServer ( UID ssID ) ;
2017-05-26 04:48:44 +08:00
private :
struct OrderByTeamKey {
bool operator ( ) ( const std : : pair < Team , KeyRange > & lhs , const std : : pair < Team , KeyRange > & rhs ) const {
if ( lhs . first < rhs . first ) return true ;
if ( lhs . first > rhs . first ) return false ;
return lhs . second . begin < rhs . second . begin ;
}
} ;
2018-11-13 10:42:29 +08:00
KeyRangeMap < std : : pair < vector < Team > , vector < Team > > > shard_teams ; // A shard can be affected by the failure of multiple teams if it is a queued merge, or when usable_regions > 1
2017-05-26 04:48:44 +08:00
std : : set < std : : pair < Team , KeyRange > , OrderByTeamKey > team_shards ;
std : : map < UID , int > storageServerShards ;
void erase ( Team team , KeyRange const & range ) ;
void insert ( Team team , KeyRange const & range ) ;
} ;
2018-07-01 09:44:46 +08:00
// DDShardInfo is so named to avoid link-time name collision with ShardInfo within the StorageServer
struct DDShardInfo {
2018-03-09 02:50:05 +08:00
Key key ;
vector < UID > primarySrc ;
vector < UID > remoteSrc ;
vector < UID > primaryDest ;
vector < UID > remoteDest ;
bool hasDest ;
2018-07-01 09:44:46 +08:00
explicit DDShardInfo ( Key key ) : key ( key ) , hasDest ( false ) { }
2018-03-09 02:50:05 +08:00
} ;
2017-05-26 04:48:44 +08:00
struct InitialDataDistribution : ReferenceCounted < InitialDataDistribution > {
int mode ;
vector < std : : pair < StorageServerInterface , ProcessClass > > allServers ;
2018-03-09 02:50:05 +08:00
std : : set < vector < UID > > primaryTeams ;
std : : set < vector < UID > > remoteTeams ;
2018-07-01 09:44:46 +08:00
vector < DDShardInfo > shards ;
2019-07-10 07:09:51 +08:00
Optional < Key > initHealthyZoneValue ;
2017-05-26 04:48:44 +08:00
} ;
2020-10-01 03:22:23 +08:00
struct ShardMetrics {
StorageMetrics metrics ;
double lastLowBandwidthStartTime ;
2020-10-28 00:11:56 +08:00
int shardCount ; // number of smaller shards whose metrics are aggregated in the ShardMetrics
2020-10-01 03:22:23 +08:00
bool operator = = ( ShardMetrics const & rhs ) const {
return metrics = = rhs . metrics & & lastLowBandwidthStartTime = = rhs . lastLowBandwidthStartTime & &
shardCount = = rhs . shardCount ;
}
ShardMetrics ( StorageMetrics const & metrics , double lastLowBandwidthStartTime , int shardCount )
: metrics ( metrics ) , lastLowBandwidthStartTime ( lastLowBandwidthStartTime ) , shardCount ( shardCount ) { }
} ;
struct ShardTrackedData {
Future < Void > trackShard ;
Future < Void > trackBytes ;
Reference < AsyncVar < Optional < ShardMetrics > > > stats ;
} ;
2020-12-05 07:58:42 +08:00
ACTOR Future < Void > dataDistributionTracker ( Reference < InitialDataDistribution > initData , Database cx ,
PromiseStream < RelocateShard > output ,
Reference < ShardsAffectedByTeamFailure > shardsAffectedByTeamFailure ,
PromiseStream < GetMetricsRequest > getShardMetrics ,
PromiseStream < GetMetricsListRequest > getShardMetricsList ,
FutureStream < Promise < int64_t > > getAverageShardBytes ,
Promise < Void > readyToStart , Reference < AsyncVar < bool > > zeroHealthyTeams ,
UID distributorId , KeyRangeMap < ShardTrackedData > * shards ,
2021-02-11 09:13:19 +08:00
bool * trackerCancelled ) ;
2020-09-28 06:26:50 +08:00
ACTOR Future < Void > dataDistributionQueue (
2020-10-22 09:22:08 +08:00
Database cx ,
PromiseStream < RelocateShard > output ,
FutureStream < RelocateShard > input ,
PromiseStream < GetMetricsRequest > getShardMetrics ,
Reference < AsyncVar < bool > > processingUnhealthy ,
vector < TeamCollectionInterface > teamCollection ,
Reference < ShardsAffectedByTeamFailure > shardsAffectedByTeamFailure ,
MoveKeysLock lock ,
PromiseStream < Promise < int64_t > > getAverageShardBytes ,
UID distributorId ,
int teamSize ,
int singleRegionTeamSize ,
double * lastLimited ,
const DDEnabledState * ddEnabledState ) ;
2017-05-26 04:48:44 +08:00
//Holds the permitted size and IO Bounds for a shard
struct ShardSizeBounds {
StorageMetrics max ;
StorageMetrics min ;
StorageMetrics permittedError ;
bool operator = = ( ShardSizeBounds const & rhs ) const {
return max = = rhs . max & & min = = rhs . min & & permittedError = = rhs . permittedError ;
}
} ;
//Gets the permitted size and IO bounds for a shard
ShardSizeBounds getShardSizeBounds ( KeyRangeRef shard , int64_t maxShardSize ) ;
//Determines the maximum shard size based on the size of the database
2018-08-10 03:37:46 +08:00
int64_t getMaxShardSize ( double dbSizeEstimate ) ;
2019-02-07 15:34:56 +08:00
2019-03-27 05:18:25 +08:00
struct DDTeamCollection ;
2019-02-15 08:24:46 +08:00
ACTOR Future < vector < std : : pair < StorageServerInterface , ProcessClass > > > getServerListAndProcessClasses ( Transaction * tr ) ;
2019-03-06 02:29:37 +08:00
2019-04-06 01:36:38 +08:00
# include "flow/unactorcompiler.h"
2019-03-06 02:29:37 +08:00
# endif