fix: split metrics could fail an assert in a very rare scenario

This commit is contained in:
Evan Tschannen 2018-01-08 18:20:22 -08:00
parent 0e7d538c94
commit 370e8a9903
1 changed files with 7 additions and 7 deletions

View File

@ -269,7 +269,7 @@ struct StorageServerMetrics {
// This function can run on untrusted user data. We must validate all divisions carefully. // This function can run on untrusted user data. We must validate all divisions carefully.
KeyRef getSplitKey( int64_t remaining, int64_t estimated, int64_t limits, int64_t used, int64_t infinity, KeyRef getSplitKey( int64_t remaining, int64_t estimated, int64_t limits, int64_t used, int64_t infinity,
bool isLastShard, StorageMetricSample& sample, double divisor, KeyRef const& lastKey, KeyRef const& key ) bool isLastShard, StorageMetricSample& sample, double divisor, KeyRef const& lastKey, KeyRef const& key, bool hasUsed )
{ {
ASSERT(remaining >= 0); ASSERT(remaining >= 0);
ASSERT(limits > 0); ASSERT(limits > 0);
@ -290,7 +290,7 @@ struct StorageServerMetrics {
// This does the conversion from native units to bytes using the divisor. // This does the conversion from native units to bytes using the divisor.
double offset = (expectedSize - used) / divisor; double offset = (expectedSize - used) / divisor;
if( offset <= 0 ) if( offset <= 0 )
return lastKey; return hasUsed ? lastKey : key;
return sample.splitEstimate( KeyRangeRef(lastKey, key), offset * ( ( 1.0 - SERVER_KNOBS->SPLIT_JITTER_AMOUNT ) + 2 * g_random->random01() * SERVER_KNOBS->SPLIT_JITTER_AMOUNT ) ); return sample.splitEstimate( KeyRangeRef(lastKey, key), offset * ( ( 1.0 - SERVER_KNOBS->SPLIT_JITTER_AMOUNT ) + 2 * g_random->random01() * SERVER_KNOBS->SPLIT_JITTER_AMOUNT ) );
} }
} }
@ -312,16 +312,16 @@ struct StorageServerMetrics {
if( remaining.bytes < 2*SERVER_KNOBS->MIN_SHARD_BYTES ) if( remaining.bytes < 2*SERVER_KNOBS->MIN_SHARD_BYTES )
break; break;
KeyRef key = req.keys.end; KeyRef key = req.keys.end;
bool hasUsed = used.bytes != 0 || used.bytesPerKSecond != 0 || used.iosPerKSecond != 0;
key = getSplitKey( remaining.bytes, estimated.bytes, req.limits.bytes, used.bytes, key = getSplitKey( remaining.bytes, estimated.bytes, req.limits.bytes, used.bytes,
req.limits.infinity, req.isLastShard, byteSample, 1, lastKey, key ); req.limits.infinity, req.isLastShard, byteSample, 1, lastKey, key, hasUsed );
if( used.bytes < SERVER_KNOBS->MIN_SHARD_BYTES ) if( used.bytes < SERVER_KNOBS->MIN_SHARD_BYTES )
key = std::max( key, byteSample.splitEstimate( KeyRangeRef(lastKey, req.keys.end), SERVER_KNOBS->MIN_SHARD_BYTES - used.bytes ) ); key = std::max( key, byteSample.splitEstimate( KeyRangeRef(lastKey, req.keys.end), SERVER_KNOBS->MIN_SHARD_BYTES - used.bytes ) );
key = getSplitKey( remaining.iosPerKSecond, estimated.iosPerKSecond, req.limits.iosPerKSecond, used.iosPerKSecond, key = getSplitKey( remaining.iosPerKSecond, estimated.iosPerKSecond, req.limits.iosPerKSecond, used.iosPerKSecond,
req.limits.infinity, req.isLastShard, iopsSample, SERVER_KNOBS->STORAGE_METRICS_AVERAGE_INTERVAL_PER_KSECONDS, lastKey, key ); req.limits.infinity, req.isLastShard, iopsSample, SERVER_KNOBS->STORAGE_METRICS_AVERAGE_INTERVAL_PER_KSECONDS, lastKey, key, hasUsed );
key = getSplitKey( remaining.bytesPerKSecond, estimated.bytesPerKSecond, req.limits.bytesPerKSecond, used.bytesPerKSecond, key = getSplitKey( remaining.bytesPerKSecond, estimated.bytesPerKSecond, req.limits.bytesPerKSecond, used.bytesPerKSecond,
req.limits.infinity, req.isLastShard, bandwidthSample, SERVER_KNOBS->STORAGE_METRICS_AVERAGE_INTERVAL_PER_KSECONDS, lastKey, key ); req.limits.infinity, req.isLastShard, bandwidthSample, SERVER_KNOBS->STORAGE_METRICS_AVERAGE_INTERVAL_PER_KSECONDS, lastKey, key, hasUsed );
ASSERT( key != lastKey || used.bytes != 0 || used.bytesPerKSecond != 0 || used.iosPerKSecond != 0); ASSERT( key != lastKey || hasUsed);
if( key == req.keys.end ) if( key == req.keys.end )
break; break;
reply.splits.push_back_deep( reply.splits.arena(), key ); reply.splits.push_back_deep( reply.splits.arena(), key );