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"
2018-10-20 01:30:13 +08:00
# include "fdbserver/ClusterRecruitmentInterface.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 ) { }
} ;
// Higher priorities are executed first
// Priority/100 is the "priority group"/"superpriority". Priority inversion
// is possible within but not between priority groups; fewer priority groups
// mean better worst case time bounds
enum {
PRIORITY_REBALANCE_SHARD = 100 ,
PRIORITY_RECOVER_MOVE = 110 ,
PRIORITY_REBALANCE_UNDERUTILIZED_TEAM = 120 ,
PRIORITY_REBALANCE_OVERUTILIZED_TEAM = 121 ,
PRIORITY_TEAM_HEALTHY = 140 ,
PRIORITY_TEAM_CONTAINS_UNDESIRED_SERVER = 150 ,
2019-07-17 09:02:36 +08:00
// Set removing_redundant_team priority lower than merge/split_shard_priority,
// so that removing redundant teams does not block merge/split shards.
2019-07-20 04:30:40 +08:00
PRIORITY_TEAM_REDUNDANT = 200 ,
2019-07-17 09:02:36 +08:00
2019-07-20 04:30:40 +08:00
PRIORITY_MERGE_SHARD = 340 ,
PRIORITY_SPLIT_SHARD = 350 ,
2017-05-26 04:48:44 +08:00
PRIORITY_TEAM_UNHEALTHY = 800 ,
PRIORITY_TEAM_2_LEFT = 809 ,
PRIORITY_TEAM_1_LEFT = 900 ,
PRIORITY_TEAM_0_LEFT = 999
} ;
enum {
SOME_SHARED = 2 ,
NONE_SHARED = 3
} ;
struct IDataDistributionTeam {
virtual vector < StorageServerInterface > getLastKnownServerInterfaces ( ) = 0 ;
2018-02-03 03:46:04 +08:00
virtual int size ( ) = 0 ;
2017-05-26 04:48:44 +08:00
virtual vector < UID > const & getServerIDs ( ) = 0 ;
virtual void addDataInFlightToTeam ( int64_t delta ) = 0 ;
virtual int64_t getDataInFlightToTeam ( ) = 0 ;
virtual int64_t getLoadBytes ( bool includeInFlight = true , double inflightPenalty = 1.0 ) = 0 ;
virtual int64_t getMinFreeSpace ( bool includeInFlight = true ) = 0 ;
virtual double getMinFreeSpaceRatio ( bool includeInFlight = true ) = 0 ;
virtual bool hasHealthyFreeSpace ( ) = 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 ;
virtual bool isHealthy ( ) = 0 ;
virtual void setHealthy ( bool ) = 0 ;
virtual int getPriority ( ) = 0 ;
virtual void setPriority ( int ) = 0 ;
virtual bool isOptimal ( ) = 0 ;
virtual bool isWrongConfiguration ( ) = 0 ;
virtual void setWrongConfiguration ( bool ) = 0 ;
2017-10-11 01:36:33 +08:00
virtual void addServers ( const vector < UID > & servers ) = 0 ;
2017-05-26 04:48:44 +08:00
std : : string getDesc ( ) {
const auto & servers = getLastKnownServerInterfaces ( ) ;
std : : string s = format ( " Size %d; " , servers . size ( ) ) ;
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 ;
double inflightPenalty ;
std : : vector < UID > sources ;
2018-02-03 03:46:04 +08:00
std : : vector < UID > completeSources ;
2017-05-26 04:48:44 +08:00
Promise < Optional < Reference < IDataDistributionTeam > > > reply ;
GetTeamRequest ( ) { }
2018-02-03 03:46:04 +08:00
GetTeamRequest ( bool wantsNewServers , bool wantsTrueBest , bool preferLowerUtilization , double inflightPenalty = 1.0 ) : wantsNewServers ( wantsNewServers ) , wantsTrueBest ( wantsTrueBest ) , preferLowerUtilization ( preferLowerUtilization ) , inflightPenalty ( inflightPenalty ) { }
2017-05-26 04:48:44 +08:00
} ;
struct GetMetricsRequest {
KeyRange keys ;
Promise < StorageMetrics > reply ;
GetMetricsRequest ( ) { }
GetMetricsRequest ( KeyRange const & keys ) : keys ( keys ) { }
} ;
struct TeamCollectionInterface {
PromiseStream < GetTeamRequest > getTeam ;
} ;
class ShardsAffectedByTeamFailure : public ReferenceCounted < ShardsAffectedByTeamFailure > {
public :
ShardsAffectedByTeamFailure ( ) { }
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 ;
return servers < r . servers ;
}
bool operator = = ( const Team & r ) const {
return servers = = r . servers & & primary = = r . primary ;
}
} ;
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.
int getNumberOfShards ( UID ssID ) ;
vector < KeyRange > getShardsFor ( Team team ) ;
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 ( ) ;
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 ;
2017-05-26 04:48:44 +08:00
} ;
Future < Void > dataDistributionTracker (
Reference < InitialDataDistribution > const & initData ,
Database const & cx ,
PromiseStream < RelocateShard > const & output ,
2018-08-10 03:37:46 +08:00
Reference < ShardsAffectedByTeamFailure > const & shardsAffectedByTeamFailure ,
2017-05-26 04:48:44 +08:00
PromiseStream < GetMetricsRequest > const & getShardMetrics ,
FutureStream < Promise < int64_t > > const & getAverageShardBytes ,
Promise < Void > const & readyToStart ,
2018-02-03 03:46:04 +08:00
Reference < AsyncVar < bool > > const & zeroHealthyTeams ,
2018-12-14 05:31:37 +08:00
UID const & distributorId ) ;
2017-05-26 04:48:44 +08:00
Future < Void > dataDistributionQueue (
Database const & cx ,
2018-08-10 03:37:46 +08:00
PromiseStream < RelocateShard > const & output ,
FutureStream < RelocateShard > const & input ,
2017-05-26 04:48:44 +08:00
PromiseStream < GetMetricsRequest > const & getShardMetrics ,
2018-04-09 12:24:05 +08:00
Reference < AsyncVar < bool > > const & processingUnhealthy ,
2017-10-11 01:36:33 +08:00
vector < TeamCollectionInterface > const & teamCollection ,
2017-05-26 04:48:44 +08:00
Reference < ShardsAffectedByTeamFailure > const & shardsAffectedByTeamFailure ,
MoveKeysLock const & lock ,
PromiseStream < Promise < int64_t > > const & getAverageShardBytes ,
2018-12-14 05:31:37 +08:00
UID const & distributorId ,
2019-03-08 02:15:28 +08:00
int const & teamSize ,
double * const & lastLimited ) ;
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