-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Enhancing Table Size API to return table size per replica #10812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,21 +85,30 @@ public TableSizeDetails getTableSizeDetails(@Nonnull String tableName, @Nonnegat | |
| TableConfig realtimeTableConfig = | ||
| ZKMetadataProvider.getRealtimeTableConfig(_helixResourceManager.getPropertyStore(), tableName); | ||
|
|
||
| if (offlineTableConfig == null && realtimeTableConfig == null) { | ||
| boolean hasRealtimeTableConfig = (realtimeTableConfig != null); | ||
| boolean hasOfflineTableConfig = (offlineTableConfig != null); | ||
| boolean isMissingAllRealtimeSegments = false; | ||
| boolean isMissingAllOfflineSegments = false; | ||
|
|
||
| if (!hasRealtimeTableConfig && !hasOfflineTableConfig) { | ||
| return null; | ||
| } | ||
| TableSizeDetails tableSizeDetails = new TableSizeDetails(tableName); | ||
| if (realtimeTableConfig != null) { | ||
| if (hasRealtimeTableConfig) { | ||
| String realtimeTableName = TableNameBuilder.REALTIME.tableNameWithType(tableName); | ||
| tableSizeDetails._realtimeSegments = getTableSubtypeSize(realtimeTableName, timeoutMsec); | ||
| tableSizeDetails._reportedSizeInBytes += tableSizeDetails._realtimeSegments._reportedSizeInBytes; | ||
| tableSizeDetails._estimatedSizeInBytes += tableSizeDetails._realtimeSegments._estimatedSizeInBytes; | ||
|
|
||
| // taking max(0,value) as values as set to -1 if all the segments are in error | ||
| tableSizeDetails._reportedSizeInBytes += Math.max(tableSizeDetails._realtimeSegments._reportedSizeInBytes, 0L); | ||
| tableSizeDetails._estimatedSizeInBytes += Math.max(tableSizeDetails._realtimeSegments._estimatedSizeInBytes, 0L); | ||
| tableSizeDetails._reportedSizePerReplicaInBytes += | ||
| Math.max(tableSizeDetails._realtimeSegments._reportedSizePerReplicaInBytes, 0L); | ||
| isMissingAllRealtimeSegments = | ||
| (tableSizeDetails._realtimeSegments._missingSegments == tableSizeDetails._realtimeSegments._segments.size()); | ||
| _controllerMetrics.setValueOfTableGauge(realtimeTableName, ControllerGauge.TABLE_TOTAL_SIZE_ON_SERVER, | ||
| tableSizeDetails._realtimeSegments._estimatedSizeInBytes); | ||
| _controllerMetrics.setValueOfTableGauge(realtimeTableName, ControllerGauge.TABLE_SIZE_PER_REPLICA_ON_SERVER, | ||
| tableSizeDetails._realtimeSegments._estimatedSizeInBytes / _helixResourceManager.getNumReplicas( | ||
| realtimeTableConfig)); | ||
| tableSizeDetails._realtimeSegments._estimatedSizeInBytes / _helixResourceManager | ||
| .getNumReplicas(realtimeTableConfig)); | ||
|
|
||
| long largestSegmentSizeOnServer = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| for (SegmentSizeDetails segmentSizeDetail : tableSizeDetails._realtimeSegments._segments.values()) { | ||
|
|
@@ -108,22 +117,25 @@ public TableSizeDetails getTableSizeDetails(@Nonnull String tableName, @Nonnegat | |
| } | ||
| } | ||
| if (largestSegmentSizeOnServer != DEFAULT_SIZE_WHEN_MISSING_OR_ERROR) { | ||
| _controllerMetrics.setValueOfTableGauge(realtimeTableName, | ||
| ControllerGauge.LARGEST_SEGMENT_SIZE_ON_SERVER, | ||
| _controllerMetrics.setValueOfTableGauge(realtimeTableName, ControllerGauge.LARGEST_SEGMENT_SIZE_ON_SERVER, | ||
| largestSegmentSizeOnServer); | ||
| } | ||
| } | ||
| if (offlineTableConfig != null) { | ||
| if (hasOfflineTableConfig) { | ||
| String offlineTableName = TableNameBuilder.OFFLINE.tableNameWithType(tableName); | ||
| tableSizeDetails._offlineSegments = getTableSubtypeSize(offlineTableName, timeoutMsec); | ||
| tableSizeDetails._reportedSizeInBytes += tableSizeDetails._offlineSegments._reportedSizeInBytes; | ||
| tableSizeDetails._estimatedSizeInBytes += tableSizeDetails._offlineSegments._estimatedSizeInBytes; | ||
|
|
||
| // taking max(0,value) as values as set to -1 if all the segments are in error | ||
| tableSizeDetails._reportedSizeInBytes += Math.max(tableSizeDetails._offlineSegments._reportedSizeInBytes, 0L); | ||
| tableSizeDetails._estimatedSizeInBytes += Math.max(tableSizeDetails._offlineSegments._estimatedSizeInBytes, 0L); | ||
| tableSizeDetails._reportedSizePerReplicaInBytes += | ||
| Math.max(tableSizeDetails._offlineSegments._reportedSizePerReplicaInBytes, 0L); | ||
| isMissingAllOfflineSegments = | ||
| (tableSizeDetails._offlineSegments._missingSegments == tableSizeDetails._offlineSegments._segments.size()); | ||
| _controllerMetrics.setValueOfTableGauge(offlineTableName, ControllerGauge.TABLE_TOTAL_SIZE_ON_SERVER, | ||
| tableSizeDetails._offlineSegments._estimatedSizeInBytes); | ||
| _controllerMetrics.setValueOfTableGauge(offlineTableName, ControllerGauge.TABLE_SIZE_PER_REPLICA_ON_SERVER, | ||
| tableSizeDetails._offlineSegments._estimatedSizeInBytes / _helixResourceManager.getNumReplicas( | ||
| offlineTableConfig)); | ||
| tableSizeDetails._offlineSegments._estimatedSizeInBytes / _helixResourceManager | ||
| .getNumReplicas(offlineTableConfig)); | ||
|
|
||
| long largestSegmentSizeOnServer = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| for (SegmentSizeDetails segmentSizeDetail : tableSizeDetails._offlineSegments._segments.values()) { | ||
|
|
@@ -132,12 +144,19 @@ public TableSizeDetails getTableSizeDetails(@Nonnull String tableName, @Nonnegat | |
| } | ||
| } | ||
| if (largestSegmentSizeOnServer != DEFAULT_SIZE_WHEN_MISSING_OR_ERROR) { | ||
| _controllerMetrics.setValueOfTableGauge(offlineTableName, | ||
| ControllerGauge.LARGEST_SEGMENT_SIZE_ON_SERVER, | ||
| _controllerMetrics.setValueOfTableGauge(offlineTableName, ControllerGauge.LARGEST_SEGMENT_SIZE_ON_SERVER, | ||
| largestSegmentSizeOnServer); | ||
| } | ||
| } | ||
|
|
||
| // Set the top level sizes to DEFAULT_SIZE_WHEN_MISSING_OR_ERROR when all segments are error | ||
| if ((hasRealtimeTableConfig && hasOfflineTableConfig && isMissingAllRealtimeSegments && isMissingAllOfflineSegments) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| || (hasOfflineTableConfig && !hasRealtimeTableConfig && isMissingAllOfflineSegments) || (hasRealtimeTableConfig | ||
| && !hasOfflineTableConfig && isMissingAllRealtimeSegments)) { | ||
| tableSizeDetails._reportedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| tableSizeDetails._estimatedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| tableSizeDetails._reportedSizePerReplicaInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| } | ||
| return tableSizeDetails; | ||
| } | ||
|
|
||
|
|
@@ -158,6 +177,10 @@ static public class TableSizeDetails { | |
| @JsonProperty("estimatedSizeInBytes") | ||
| public long _estimatedSizeInBytes = 0; | ||
|
|
||
| // reported size per replica | ||
| @JsonProperty("reportedSizePerReplicaInBytes") | ||
| public long _reportedSizePerReplicaInBytes = 0; | ||
|
|
||
| @JsonProperty("offlineSegments") | ||
| public TableSubTypeSizeDetails _offlineSegments; | ||
|
|
||
|
|
@@ -186,6 +209,10 @@ static public class TableSubTypeSizeDetails { | |
| @JsonProperty("missingSegments") | ||
| public int _missingSegments = 0; | ||
|
|
||
| // reported size per replica | ||
| @JsonProperty("reportedSizePerReplicaInBytes") | ||
| public long _reportedSizePerReplicaInBytes = 0; | ||
|
|
||
| @JsonProperty("segments") | ||
| public Map<String, SegmentSizeDetails> _segments = new HashMap<>(); | ||
| } | ||
|
|
@@ -198,6 +225,10 @@ static public class SegmentSizeDetails { | |
| @JsonProperty("estimatedSizeInBytes") | ||
| public long _estimatedSizeInBytes = 0; | ||
|
|
||
| // Max Reported size per replica | ||
| @JsonProperty("maxReportedSizePerReplicaInBytes") | ||
| public long _maxReportedSizePerReplicaInBytes = 0; | ||
|
|
||
| @JsonProperty("serverInfo") | ||
| public Map<String, SegmentSizeInfo> _serverInfo = new HashMap<>(); | ||
| } | ||
|
|
@@ -248,25 +279,29 @@ public TableSubTypeSizeDetails getTableSubtypeSize(String tableNameWithType, int | |
| String segment = entry.getKey(); | ||
| SegmentSizeDetails sizeDetails = entry.getValue(); | ||
| // Iterate over all segment size info, update reported size, track max segment size and number of errored servers | ||
| long segmentLevelMax = -1L; | ||
| sizeDetails._maxReportedSizePerReplicaInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| int errors = 0; | ||
| for (SegmentSizeInfo sizeInfo : sizeDetails._serverInfo.values()) { | ||
| if (sizeInfo.getDiskSizeInBytes() != DEFAULT_SIZE_WHEN_MISSING_OR_ERROR) { | ||
| sizeDetails._reportedSizeInBytes += sizeInfo.getDiskSizeInBytes(); | ||
| segmentLevelMax = Math.max(segmentLevelMax, sizeInfo.getDiskSizeInBytes()); | ||
| sizeDetails._maxReportedSizePerReplicaInBytes = | ||
| Math.max(sizeDetails._maxReportedSizePerReplicaInBytes, sizeInfo.getDiskSizeInBytes()); | ||
| } else { | ||
| errors++; | ||
| } | ||
| } | ||
| // Update estimated size, track segments that are missing from all servers | ||
| if (errors != sizeDetails._serverInfo.size()) { | ||
| // Use max segment size from other servers to estimate the segment size not reported | ||
| sizeDetails._estimatedSizeInBytes = sizeDetails._reportedSizeInBytes + errors * segmentLevelMax; | ||
| sizeDetails._estimatedSizeInBytes = | ||
| sizeDetails._reportedSizeInBytes + (errors * sizeDetails._maxReportedSizePerReplicaInBytes); | ||
| subTypeSizeDetails._reportedSizeInBytes += sizeDetails._reportedSizeInBytes; | ||
| subTypeSizeDetails._estimatedSizeInBytes += sizeDetails._estimatedSizeInBytes; | ||
| subTypeSizeDetails._reportedSizePerReplicaInBytes += sizeDetails._maxReportedSizePerReplicaInBytes; | ||
| } else { | ||
| // Segment is missing from all servers | ||
| missingSegments.add(segment); | ||
| sizeDetails._maxReportedSizePerReplicaInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| sizeDetails._reportedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| sizeDetails._estimatedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| subTypeSizeDetails._missingSegments++; | ||
|
|
@@ -284,6 +319,7 @@ public TableSubTypeSizeDetails getTableSubtypeSize(String tableNameWithType, int | |
| LOGGER.warn("Failed to get size report for all {} segments of table: {}", numSegments, tableNameWithType); | ||
| subTypeSizeDetails._reportedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| subTypeSizeDetails._estimatedSizeInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| subTypeSizeDetails._reportedSizePerReplicaInBytes = DEFAULT_SIZE_WHEN_MISSING_OR_ERROR; | ||
| } else { | ||
| LOGGER.warn("Missing size report for {} out of {} segments for table {}", subTypeSizeDetails._missingSegments, | ||
| numSegments, tableNameWithType); | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you please help me understand the reason for this decision?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To explicitly say in response that segments are in error ( and its not 0 sized ). However, the much more correct way for the caller to identify is to look into "missingSegment" property.
With the existing implementation, this would return as "-2" which kind of diverges from the default error value we use , so I move this section at the end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please help me understand why the condition is "when all segments are error". What is the major difference between "when all segments are error" and "when some segments are in error state"?
Say that a table has 1k segments, the current logic set the top level size to -1 when all 1k segments are in error state, but will not set the level size to -1 when only 1 segment is in good state. What is the major difference here?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assume the case for hybrid Table with all the segments missing .
The current implementation would have value as "-2" ( This is due to both realtime & offline block adding "-1" ). This is what I have tried to explain in my previous comment