diff --git a/docs/reference/cluster/nodes-stats.asciidoc b/docs/reference/cluster/nodes-stats.asciidoc index 8287787392146..dd3ec9a533a00 100644 --- a/docs/reference/cluster/nodes-stats.asciidoc +++ b/docs/reference/cluster/nodes-stats.asciidoc @@ -256,6 +256,16 @@ Total size of all shards assigned to the node. (integer) Total size, in bytes, of all shards assigned to the node. +`total_data_set_size`:: +(<>) +Total data set size of all shards assigned to the node. +This includes the size of shards not stored fully on the node (shared cache searchable snapshots). + +`total_data_set_size_in_bytes`:: +(integer) +Total data set size, in bytes, of all shards assigned to the node. +This includes the size of shards not stored fully on the node (shared cache searchable snapshots). + `reserved`:: (<>) A prediction of how much larger the shard stores on this node will eventually diff --git a/docs/reference/cluster/stats.asciidoc b/docs/reference/cluster/stats.asciidoc index 3e375ce519cda..fdf50314cce5d 100644 --- a/docs/reference/cluster/stats.asciidoc +++ b/docs/reference/cluster/stats.asciidoc @@ -240,6 +240,16 @@ Total size of all shards assigned to selected nodes. (integer) Total size, in bytes, of all shards assigned to selected nodes. +`total_data_set_size`:: +(<>) +Total data set size of all shards assigned to selected nodes. +This includes the size of shards not stored fully on the nodes (shared cache searchable snapshots). + +`total_data_set_size_in_bytes`:: +(integer) +Total data set size, in bytes, of all shards assigned to selected nodes. +This includes the size of shards not stored fully on the nodes (shared cache searchable snapshots). + `reserved`:: (<>) A prediction of how much larger the shard stores will eventually grow due to @@ -1238,6 +1248,8 @@ The API returns the following response: "store": { "size": "16.2kb", "size_in_bytes": 16684, + "total_data_set_size": "16.2kb", + "total_data_set_size_in_bytes": 16684, "reserved": "0b", "reserved_in_bytes": 0 }, diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/nodes.stats/40_store_stats.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/nodes.stats/40_store_stats.yml index accfbd4cd7cda..502c258181f2e 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/nodes.stats/40_store_stats.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/nodes.stats/40_store_stats.yml @@ -1,9 +1,35 @@ --- "Store stats": - skip: - version: " - 7.99.99" - reason: "reserved_in_bytes field is not returned in prior versions" features: [arbitrary_key] + version: " - 7.12.99" + reason: "total_data_set_size added in 7.13" + + - do: + nodes.info: + node_id: _master + - set: + nodes._arbitrary_key_: master + + - do: + nodes.stats: + metric: [ indices ] + index_metric: [ store ] + + - is_false: nodes.$master.discovery + - is_true: nodes.$master.indices.store + - gte: { nodes.$master.indices.store.size_in_bytes: 0 } + - gte: { nodes.$master.indices.store.reserved_in_bytes: -1 } + - set: + nodes.$master.indices.store.size_in_bytes: size_in_bytes + - match: { nodes.$master.indices.store.total_data_set_size_in_bytes: $size_in_bytes } + +--- +"Store stats bwc": + - skip: + features: [arbitrary_key] + version: " - 7.8.99" + reason: "reserved_in_bytes field is not returned in prior versions" - do: nodes.info: diff --git a/server/src/main/java/org/elasticsearch/index/IndexService.java b/server/src/main/java/org/elasticsearch/index/IndexService.java index 4ff637f5582a6..3830ddb1573ce 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexService.java +++ b/server/src/main/java/org/elasticsearch/index/IndexService.java @@ -92,6 +92,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.LongSupplier; +import java.util.function.LongUnaryOperator; import java.util.function.Supplier; import static java.util.Collections.emptyMap; @@ -373,7 +374,7 @@ private long getAvgShardSizeInBytes() throws IOException { long sum = 0; int count = 0; for (IndexShard indexShard : this) { - sum += indexShard.store().stats(0L).sizeInBytes(); + sum += indexShard.store().stats(0L, LongUnaryOperator.identity()).sizeInBytes(); count++; } if (count == 0) { diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java index 21b4b879fb0ce..3fcd8aa762189 100644 --- a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -180,6 +180,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.LongSupplier; +import java.util.function.LongUnaryOperator; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -1089,15 +1090,16 @@ public GetStats getStats() { } public StoreStats storeStats() { - if (DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS.get(indexSettings.getSettings())) { - // if this shard has no disk footprint then its size is reported as 0 - return new StoreStats(0, 0); - } try { final RecoveryState recoveryState = this.recoveryState; - final long bytesStillToRecover = recoveryState == null ? -1L : recoveryState.getIndex().bytesStillToRecover(); - final long reservedBytes = bytesStillToRecover == -1 ? StoreStats.UNKNOWN_RESERVED_BYTES : bytesStillToRecover; - return store.stats(reservedBytes); + if (DiskThresholdDecider.SETTING_IGNORE_DISK_WATERMARKS.get(indexSettings.getSettings())) { + // if this shard has no disk footprint then its local size is reported as 0 + return store.stats(0, size -> 0); + } else { + final long bytesStillToRecover = recoveryState == null ? -1L : recoveryState.getIndex().bytesStillToRecover(); + final long reservedBytes = bytesStillToRecover == -1 ? StoreStats.UNKNOWN_RESERVED_BYTES : bytesStillToRecover; + return store.stats(reservedBytes, LongUnaryOperator.identity()); + } } catch (IOException e) { failShard("Failing shard because of exception during storeStats", e); throw new ElasticsearchException("io exception while building 'store stats'", e); diff --git a/server/src/main/java/org/elasticsearch/index/store/Store.java b/server/src/main/java/org/elasticsearch/index/store/Store.java index 380f83558e8a2..68bd5d93749c4 100644 --- a/server/src/main/java/org/elasticsearch/index/store/Store.java +++ b/server/src/main/java/org/elasticsearch/index/store/Store.java @@ -91,6 +91,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; +import java.util.function.LongUnaryOperator; import java.util.zip.CRC32; import java.util.zip.Checksum; @@ -346,10 +347,12 @@ public CheckIndex.Status checkIndex(PrintStream out) throws IOException { /** * @param reservedBytes a prediction of how much larger the store is expected to grow, or {@link StoreStats#UNKNOWN_RESERVED_BYTES}. + * @param localSizeFunction to calculate the local size of the shard based on the shard size. */ - public StoreStats stats(long reservedBytes) throws IOException { + public StoreStats stats(long reservedBytes, LongUnaryOperator localSizeFunction) throws IOException { ensureOpen(); - return new StoreStats(directory.estimateSize(), reservedBytes); + long sizeInBytes = directory.estimateSize(); + return new StoreStats(localSizeFunction.applyAsLong(sizeInBytes), sizeInBytes, reservedBytes); } /** diff --git a/server/src/main/java/org/elasticsearch/index/store/StoreStats.java b/server/src/main/java/org/elasticsearch/index/store/StoreStats.java index 2d68dcfd13a56..f38d24d12281f 100644 --- a/server/src/main/java/org/elasticsearch/index/store/StoreStats.java +++ b/server/src/main/java/org/elasticsearch/index/store/StoreStats.java @@ -27,8 +27,10 @@ public class StoreStats implements Writeable, ToXContentFragment { public static final long UNKNOWN_RESERVED_BYTES = -1L; public static final Version RESERVED_BYTES_VERSION = Version.V_7_9_0; + public static final Version TOTAL_DATA_SET_SIZE_SIZE_VERSION = Version.V_7_13_0; private long sizeInBytes; + private long totalDataSetSizeInBytes; private long reservedSize; public StoreStats() { @@ -40,6 +42,11 @@ public StoreStats(StreamInput in) throws IOException { if (in.getVersion().before(Version.V_6_0_0_alpha1)) { in.readVLong(); // throttleTimeInNanos } + if (in.getVersion().onOrAfter(TOTAL_DATA_SET_SIZE_SIZE_VERSION)) { + totalDataSetSizeInBytes = in.readVLong(); + } else { + totalDataSetSizeInBytes = sizeInBytes; + } if (in.getVersion().onOrAfter(RESERVED_BYTES_VERSION)) { reservedSize = in.readZLong(); } else { @@ -49,19 +56,22 @@ public StoreStats(StreamInput in) throws IOException { /** * @param sizeInBytes the size of the store in bytes + * @param totalDataSetSizeInBytes the size of the total data set in bytes, can differ from sizeInBytes for shards using shared cache + * storage * @param reservedSize a prediction of how much larger the store is expected to grow, or {@link StoreStats#UNKNOWN_RESERVED_BYTES}. */ - public StoreStats(long sizeInBytes, long reservedSize) { + public StoreStats(long sizeInBytes, long totalDataSetSizeInBytes, long reservedSize) { assert reservedSize == UNKNOWN_RESERVED_BYTES || reservedSize >= 0 : reservedSize; this.sizeInBytes = sizeInBytes; + this.totalDataSetSizeInBytes = totalDataSetSizeInBytes; this.reservedSize = reservedSize; } - public void add(StoreStats stats) { if (stats == null) { return; } sizeInBytes += stats.sizeInBytes; + totalDataSetSizeInBytes += stats.totalDataSetSizeInBytes; reservedSize = ignoreIfUnknown(reservedSize) + ignoreIfUnknown(stats.reservedSize); } @@ -85,6 +95,14 @@ public ByteSizeValue getSize() { return size(); } + public ByteSizeValue totalDataSetSize() { + return new ByteSizeValue(totalDataSetSizeInBytes); + } + + public ByteSizeValue getTotalDataSetSize() { + return totalDataSetSize(); + } + /** * A prediction of how much larger this store will eventually grow. For instance, if we are currently doing a peer recovery or restoring * a snapshot into this store then we can account for the rest of the recovery using this field. A value of {@code -1B} indicates that @@ -100,6 +118,9 @@ public void writeTo(StreamOutput out) throws IOException { if (out.getVersion().before(Version.V_6_0_0_alpha1)) { out.writeVLong(0L); // throttleTimeInNanos } + if (out.getVersion().onOrAfter(TOTAL_DATA_SET_SIZE_SIZE_VERSION)) { + out.writeVLong(totalDataSetSizeInBytes); + } if (out.getVersion().onOrAfter(RESERVED_BYTES_VERSION)) { out.writeZLong(reservedSize); } @@ -109,6 +130,7 @@ public void writeTo(StreamOutput out) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(Fields.STORE); builder.humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, size()); + builder.humanReadableField(Fields.TOTAL_DATA_SET_SIZE_IN_BYTES, Fields.TOTAL_DATA_SET_SIZE, totalDataSetSize()); builder.humanReadableField(Fields.RESERVED_IN_BYTES, Fields.RESERVED, getReservedSize()); builder.endObject(); return builder; @@ -118,6 +140,8 @@ static final class Fields { static final String STORE = "store"; static final String SIZE = "size"; static final String SIZE_IN_BYTES = "size_in_bytes"; + static final String TOTAL_DATA_SET_SIZE = "total_data_set_size"; + static final String TOTAL_DATA_SET_SIZE_IN_BYTES = "total_data_set_size_in_bytes"; static final String RESERVED = "reserved"; static final String RESERVED_IN_BYTES = "reserved_in_bytes"; } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/stats/VersionStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/stats/VersionStatsTests.java index b801cfbe47cf6..1f0e625dce4b3 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/stats/VersionStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/stats/VersionStatsTests.java @@ -99,7 +99,7 @@ public void testCreation() { Path path = createTempDir().resolve("indices").resolve(shardRouting.shardId().getIndex().getUUID()) .resolve(String.valueOf(shardRouting.shardId().id())); IndexShard indexShard = mock(IndexShard.class); - StoreStats storeStats = new StoreStats(100, 200); + StoreStats storeStats = new StoreStats(100, 150, 200); when(indexShard.storeStats()).thenReturn(storeStats); ShardStats shardStats = new ShardStats(shardRouting, new ShardPath(false, path, path, shardRouting.shardId()), new CommonStats(null, indexShard, new CommonStatsFlags(CommonStatsFlags.Flag.Store)), diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/TransportResizeActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/TransportResizeActionTests.java index f757486f3f24a..bed88f409bcb2 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/TransportResizeActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/TransportResizeActionTests.java @@ -70,7 +70,8 @@ public void testErrorCondition() { assertTrue( expectThrows(IllegalStateException.class, () -> TransportResizeAction.prepareCreateIndexRequest(new ResizeRequest("target", "source"), state, - new StoreStats(between(1, 100), between(1, 100)), (i) -> new DocsStats(Integer.MAX_VALUE, between(1, 1000), + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), + (i) -> new DocsStats(Integer.MAX_VALUE, between(1, 1000), between(1, 100)), "target") ).getMessage().startsWith("Can't merge index with more than [2147483519] docs - too many documents in shards ")); @@ -82,7 +83,7 @@ public void testErrorCondition() { TransportResizeAction.prepareCreateIndexRequest(req, createClusterState("source", 8, 1, Settings.builder().put("index.blocks.write", true).build()).metadata().index("source"), - new StoreStats(between(1, 100), between(1, 100)), + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), (i) -> i == 2 || i == 3 ? new DocsStats(Integer.MAX_VALUE / 2, between(1, 1000), between(1, 10000)) : null , "target"); } @@ -96,7 +97,7 @@ public void testErrorCondition() { createClusterState("source", 8, 1, Settings.builder().put("index.blocks.write", true).put("index.soft_deletes.enabled", true).build()) .metadata().index("source"), - new StoreStats(between(1, 100), between(1, 100)), + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), (i) -> new DocsStats(between(10, 1000), between(1, 10), between(1, 10000)), "target"); }); assertThat(softDeletesError.getMessage(), equalTo("Can't disable [index.soft_deletes.enabled] setting on resize")); @@ -117,7 +118,7 @@ public void testErrorCondition() { clusterState = ClusterState.builder(clusterState).routingTable(routingTable).build(); TransportResizeAction.prepareCreateIndexRequest(new ResizeRequest("target", "source"), clusterState.metadata().index("source"), - new StoreStats(between(1, 100), between(1, 100)), + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), (i) -> new DocsStats(between(1, 1000), between(1, 1000), between(0, 10000)), "target"); } @@ -141,7 +142,8 @@ public void testPassNumRoutingShards() { resizeRequest.getTargetIndexRequest() .settings(Settings.builder().put("index.number_of_shards", 2).build()); IndexMetadata indexMetadata = clusterState.metadata().index("source"); - TransportResizeAction.prepareCreateIndexRequest(resizeRequest, indexMetadata, new StoreStats(between(1, 100), between(1, 100)), + TransportResizeAction.prepareCreateIndexRequest(resizeRequest, indexMetadata, + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), null, "target"); resizeRequest.getTargetIndexRequest() @@ -149,7 +151,8 @@ public void testPassNumRoutingShards() { .put("index.number_of_routing_shards", randomIntBetween(2, 10)) .put("index.number_of_shards", 2) .build()); - TransportResizeAction.prepareCreateIndexRequest(resizeRequest, indexMetadata, new StoreStats(between(1, 100), between(1, 100)), + TransportResizeAction.prepareCreateIndexRequest(resizeRequest, indexMetadata, + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), null, "target"); } @@ -174,7 +177,7 @@ public void testPassNumRoutingShardsAndFail() { resizeRequest.getTargetIndexRequest() .settings(Settings.builder().put("index.number_of_shards", numShards * 2).build()); TransportResizeAction.prepareCreateIndexRequest(resizeRequest, clusterState.metadata().index("source"), - new StoreStats(between(1, 100), between(1, 100)), null, "target"); + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), null, "target"); resizeRequest.getTargetIndexRequest() .settings(Settings.builder() @@ -183,7 +186,7 @@ public void testPassNumRoutingShardsAndFail() { ClusterState finalState = clusterState; IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> TransportResizeAction.prepareCreateIndexRequest(resizeRequest, finalState.metadata().index("source"), - new StoreStats(between(1, 100), between(1, 100)), null, "target")); + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), null, "target")); assertEquals("cannot provide index.number_of_routing_shards on resize", iae.getMessage()); } @@ -211,7 +214,8 @@ public void testShrinkIndexSettings() { final ActiveShardCount activeShardCount = randomBoolean() ? ActiveShardCount.ALL : ActiveShardCount.ONE; target.setWaitForActiveShards(activeShardCount); CreateIndexClusterStateUpdateRequest request = TransportResizeAction.prepareCreateIndexRequest( - target, clusterState.metadata().index(indexName), new StoreStats(between(1, 100), between(1, 100)), (i) -> stats, "target"); + target, clusterState.metadata().index(indexName), + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), (i) -> stats, "target"); assertNotNull(request.recoverFrom()); assertEquals(indexName, request.recoverFrom().getName()); assertEquals("1", request.settings().get("index.number_of_shards")); @@ -242,7 +246,8 @@ public void testShrinkWithMaxPrimaryShardSize() { .settings(Settings.builder().put("index.number_of_shards", 2).build()); assertTrue( expectThrows(IllegalArgumentException.class, () -> - TransportResizeAction.prepareCreateIndexRequest(resizeRequest, state, new StoreStats(between(1, 100), between(1, 100)), + TransportResizeAction.prepareCreateIndexRequest(resizeRequest, state, + new StoreStats(between(1, 100), between(0, 100), between(1, 100)), (i) -> new DocsStats(Integer.MAX_VALUE, between(1, 1000), between(1, 100)), "target") ).getMessage().startsWith("Cannot set both index.number_of_shards and max_primary_shard_size for the target index")); @@ -268,7 +273,7 @@ public void testShrinkWithMaxPrimaryShardSize() { // each shard's storage will not be greater than the `max_primary_shard_size` ResizeRequest target1 = new ResizeRequest("target", "source"); target1.setMaxPrimaryShardSize(new ByteSizeValue(2)); - StoreStats storeStats = new StoreStats(10, between(1, 100)); + StoreStats storeStats = new StoreStats(10, between(0, 100), between(1, 100)); final int targetIndexShardsNum1 = 5; final ActiveShardCount activeShardCount1 = ActiveShardCount.from(targetIndexShardsNum1); target1.setWaitForActiveShards(targetIndexShardsNum1); @@ -285,7 +290,7 @@ public void testShrinkWithMaxPrimaryShardSize() { // the shards number of the target index will be equal to the source index's shards number ResizeRequest target2 = new ResizeRequest("target2", "source"); target2.setMaxPrimaryShardSize(new ByteSizeValue(1)); - StoreStats storeStats2 = new StoreStats(100, between(1, 100)); + StoreStats storeStats2 = new StoreStats(100, between(0, 100), between(1, 100)); final int targetIndexShardsNum2 = 10; final ActiveShardCount activeShardCount2 = ActiveShardCount.from(targetIndexShardsNum2); target2.setWaitForActiveShards(activeShardCount2); diff --git a/server/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java b/server/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java index 3a40b13fc31f4..af4dfb1a95f86 100644 --- a/server/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/DiskUsageTests.java @@ -94,14 +94,14 @@ public void testFillShardLevelInfo() { test_0 = ShardRoutingHelper.moveToStarted(test_0); Path test0Path = createTempDir().resolve("indices").resolve(index.getUUID()).resolve("0"); CommonStats commonStats0 = new CommonStats(); - commonStats0.store = new StoreStats(100, 0L); + commonStats0.store = new StoreStats(100, 100, 0L); ShardRouting test_1 = ShardRouting.newUnassigned(new ShardId(index, 1), false, PeerRecoverySource.INSTANCE, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, "foo")); test_1 = ShardRoutingHelper.initialize(test_1, "node2"); test_1 = ShardRoutingHelper.moveToStarted(test_1); Path test1Path = createTempDir().resolve("indices").resolve(index.getUUID()).resolve("1"); CommonStats commonStats1 = new CommonStats(); - commonStats1.store = new StoreStats(1000, 0L); + commonStats1.store = new StoreStats(1000, 1000, 0L); ShardStats[] stats = new ShardStats[] { new ShardStats(test_0, new ShardPath(false, test0Path, test0Path, test_0.shardId()), commonStats0 , null, null, null), new ShardStats(test_1, new ShardPath(false, test1Path, test1Path, test_1.shardId()), commonStats1 , null, null, null) diff --git a/server/src/test/java/org/elasticsearch/index/store/StoreTests.java b/server/src/test/java/org/elasticsearch/index/store/StoreTests.java index 37b6470ecbfad..2621f6b687c24 100644 --- a/server/src/test/java/org/elasticsearch/index/store/StoreTests.java +++ b/server/src/test/java/org/elasticsearch/index/store/StoreTests.java @@ -77,6 +77,7 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.LongUnaryOperator; import static java.util.Collections.unmodifiableMap; import static org.elasticsearch.test.VersionUtils.randomVersion; @@ -452,7 +453,7 @@ private void corruptFile(Directory dir, String fileIn, String fileOut) throws IO public void assertDeleteContent(Store store, Directory dir) throws IOException { deleteContent(store.directory()); assertThat(Arrays.toString(store.directory().listAll()), store.directory().listAll().length, equalTo(0)); - assertThat(store.stats(0L).sizeInBytes(), equalTo(0L)); + assertThat(store.stats(0L, LongUnaryOperator.identity()).sizeInBytes(), equalTo(0L)); assertThat(dir.listAll().length, equalTo(0)); } @@ -737,19 +738,24 @@ public void testStoreStats() throws IOException { assertTrue("expected extraFS file but got: " + extraFiles, extraFiles.startsWith("extra")); initialStoreSize += store.directory().fileLength(extraFiles); } + final long localStoreSizeDelta = randomLongBetween(-initialStoreSize, initialStoreSize); final long reservedBytes = randomBoolean() ? StoreStats.UNKNOWN_RESERVED_BYTES :randomLongBetween(0L, Integer.MAX_VALUE); - StoreStats stats = store.stats(reservedBytes); - assertEquals(initialStoreSize, stats.getSize().getBytes()); + StoreStats stats = store.stats(reservedBytes, size -> size + localStoreSizeDelta); + assertEquals(initialStoreSize, stats.totalDataSetSize().getBytes()); + assertEquals(initialStoreSize + localStoreSizeDelta, stats.getSize().getBytes()); assertEquals(reservedBytes, stats.getReservedSize().getBytes()); stats.add(null); - assertEquals(initialStoreSize, stats.getSize().getBytes()); + assertEquals(initialStoreSize, stats.totalDataSetSize().getBytes()); + assertEquals(initialStoreSize + localStoreSizeDelta, stats.getSize().getBytes()); assertEquals(reservedBytes, stats.getReservedSize().getBytes()); - final long otherStatsBytes = randomLongBetween(0L, Integer.MAX_VALUE); + final long otherStatsDataSetBytes = randomLongBetween(0L, Integer.MAX_VALUE); + final long otherStatsLocalBytes = randomLongBetween(0L, Integer.MAX_VALUE); final long otherStatsReservedBytes = randomBoolean() ? StoreStats.UNKNOWN_RESERVED_BYTES :randomLongBetween(0L, Integer.MAX_VALUE); - stats.add(new StoreStats(otherStatsBytes, otherStatsReservedBytes)); - assertEquals(initialStoreSize + otherStatsBytes, stats.getSize().getBytes()); + stats.add(new StoreStats(otherStatsLocalBytes, otherStatsDataSetBytes, otherStatsReservedBytes)); + assertEquals(initialStoreSize + otherStatsDataSetBytes, stats.totalDataSetSize().getBytes()); + assertEquals(initialStoreSize + otherStatsLocalBytes + localStoreSizeDelta, stats.getSize().getBytes()); assertEquals(Math.max(reservedBytes, 0L) + Math.max(otherStatsReservedBytes, 0L), stats.getReservedSize().getBytes()); Directory dir = store.directory(); @@ -764,8 +770,9 @@ public void testStoreStats() throws IOException { } assertTrue(numNonExtraFiles(store) > 0); - stats = store.stats(0L); - assertEquals(stats.getSizeInBytes(), length + initialStoreSize); + stats = store.stats(0L, size -> size + localStoreSizeDelta); + assertEquals(initialStoreSize + length, stats.totalDataSetSize().getBytes()); + assertEquals(initialStoreSize + localStoreSizeDelta + length, stats.getSizeInBytes()); deleteContent(store.directory()); IOUtils.close(store); diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/cluster/ClusterStatsMonitoringDocTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/cluster/ClusterStatsMonitoringDocTests.java index d325d4c4453cd..def96c8e8d25f 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/cluster/ClusterStatsMonitoringDocTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/cluster/ClusterStatsMonitoringDocTests.java @@ -419,6 +419,7 @@ public void testToXContent() throws IOException { + "}," + "\"store\":{" + "\"size_in_bytes\":0," + + "\"total_data_set_size_in_bytes\":0," + "\"reserved_in_bytes\":0" + "}," + "\"fielddata\":{" diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndexStatsMonitoringDocTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndexStatsMonitoringDocTests.java index f024ed74ff062..2cef486e44792 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndexStatsMonitoringDocTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndexStatsMonitoringDocTests.java @@ -325,7 +325,7 @@ private static CommonStats mockCommonStats() { commonStats.getMerge().add(no, no, no, ++iota, no, no, no, no, no, no); commonStats.getQueryCache().add(new QueryCacheStats(++iota, ++iota, ++iota, ++iota, no)); commonStats.getRequestCache().add(new RequestCacheStats(++iota, ++iota, ++iota, ++iota)); - commonStats.getStore().add(new StoreStats(++iota, no)); + commonStats.getStore().add(new StoreStats(++iota, no, no)); commonStats.getRefresh().add(new RefreshStats(no, ++iota, no, ++iota, (int) no)); final IndexingStats.Stats indexingStats = new IndexingStats.Stats(++iota, ++iota, no, no, no, no, no, no, false, ++iota); diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndicesStatsMonitoringDocTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndicesStatsMonitoringDocTests.java index b811f20bc18fa..0011aaf2a0d4e 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndicesStatsMonitoringDocTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/indices/IndicesStatsMonitoringDocTests.java @@ -145,7 +145,7 @@ public void testToXContent() throws IOException { private CommonStats mockCommonStats() { final CommonStats commonStats = new CommonStats(CommonStatsFlags.ALL); commonStats.getDocs().add(new DocsStats(1L, 0L, randomNonNegativeLong())); - commonStats.getStore().add(new StoreStats(2L, 0L)); + commonStats.getStore().add(new StoreStats(2L, 0L, 0L)); final IndexingStats.Stats indexingStats = new IndexingStats.Stats(3L, 4L, 0L, 0L, 0L, 0L, 0L, 0L, true, 5L); commonStats.getIndexing().add(new IndexingStats(indexingStats, null)); diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/node/NodeStatsMonitoringDocTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/node/NodeStatsMonitoringDocTests.java index f8cdd9814722c..70e8fd15cde46 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/node/NodeStatsMonitoringDocTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/node/NodeStatsMonitoringDocTests.java @@ -292,7 +292,7 @@ private static NodeStats mockNodeStats() { final CommonStats indicesCommonStats = new CommonStats(CommonStatsFlags.ALL); indicesCommonStats.getDocs().add(new DocsStats(++iota, no, randomNonNegativeLong())); indicesCommonStats.getFieldData().add(new FieldDataStats(++iota, ++iota, null)); - indicesCommonStats.getStore().add(new StoreStats(++iota, no)); + indicesCommonStats.getStore().add(new StoreStats(++iota, no, no)); final IndexingStats.Stats indexingStats = new IndexingStats.Stats(++iota, ++iota, ++iota, no, no, no, no, no, false, ++iota); indicesCommonStats.getIndexing().add(new IndexingStats(indexingStats, null)); diff --git a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java index 12bad1a835960..91d0fc3fbe4d5 100644 --- a/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java +++ b/x-pack/plugin/searchable-snapshots/src/internalClusterTest/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsIntegTests.java @@ -36,6 +36,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AtomicArray; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.env.Environment; @@ -54,6 +55,8 @@ import org.elasticsearch.index.shard.IndexShardTestCase; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardPath; +import org.elasticsearch.index.store.Store; +import org.elasticsearch.index.store.StoreStats; import org.elasticsearch.indices.IndexClosedException; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.indices.recovery.RecoveryState; @@ -113,6 +116,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.lessThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.oneOf; @@ -505,6 +509,7 @@ public void testCreateAndRestorePartialSearchableSnapshot() throws Exception { expectedDataTiersPreference = getDataTiersPreference(MountSearchableSnapshotRequest.Storage.SHARED_CACHE); } + indexSettingsBuilder.put(Store.INDEX_STORE_STATS_REFRESH_INTERVAL_SETTING.getKey(), TimeValue.ZERO); final AtomicBoolean statsWatcherRunning = new AtomicBoolean(true); final Thread statsWatcher = new Thread(() -> { while (statsWatcherRunning.get()) { @@ -517,12 +522,13 @@ public void testCreateAndRestorePartialSearchableSnapshot() throws Exception { } for (ShardStats shardStats : indicesStatsResponse.getShards()) { - assertThat( - shardStats.getShardRouting().toString(), - shardStats.getStats().getStore().getReservedSize().getBytes(), - equalTo(0L) - ); - assertThat(shardStats.getShardRouting().toString(), shardStats.getStats().getStore().getSize().getBytes(), equalTo(0L)); + StoreStats store = shardStats.getStats().getStore(); + assertThat(shardStats.getShardRouting().toString(), store.getReservedSize().getBytes(), equalTo(0L)); + assertThat(shardStats.getShardRouting().toString(), store.getSize().getBytes(), equalTo(0L)); + } + if (indicesStatsResponse.getShards().length > 0) { + assertThat(indicesStatsResponse.getTotal().getStore().getReservedSize().getBytes(), equalTo(0L)); + assertThat(indicesStatsResponse.getTotal().getStore().getSize().getBytes(), equalTo(0L)); } } }, "test-stats-watcher"); @@ -542,6 +548,44 @@ public void testCreateAndRestorePartialSearchableSnapshot() throws Exception { final RestoreSnapshotResponse restoreSnapshotResponse = client().execute(MountSearchableSnapshotAction.INSTANCE, req).get(); assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0)); + final Map snapshotShards = clusterAdmin().prepareSnapshotStatus(fsRepoName) + .setSnapshots(snapshotInfo.snapshotId().getName()) + .get() + .getSnapshots() + .get(0) + .getIndices() + .get(indexName) + .getShards(); + + final IndicesStatsResponse indicesStatsResponse = client().admin() + .indices() + .prepareStats(restoredIndexName) + .clear() + .setStore(true) + .get(); + assertThat(indicesStatsResponse.getShards().length, greaterThan(0)); + long totalExpectedSize = 0; + for (ShardStats shardStats : indicesStatsResponse.getShards()) { + StoreStats store = shardStats.getStats().getStore(); + assertThat(shardStats.getShardRouting().toString(), store.getReservedSize().getBytes(), equalTo(0L)); + assertThat(shardStats.getShardRouting().toString(), store.getSize().getBytes(), equalTo(0L)); + + // the extra segments_N file created for bootstrap new history and associate translog makes us unable to precisely assert this. + final long expectedSize = snapshotShards.get(shardStats.getShardRouting().getId()).getStats().getTotalSize(); + assertThat(shardStats.getShardRouting().toString(), store.getTotalDataSetSize().getBytes(), greaterThanOrEqualTo(expectedSize)); + // the extra segments_N file only has a new history UUID and translog UUID, both of which have constant size. It's size is + // therefore identical to the original segments_N file from the snapshot. We expect at least 1 byte of other content, making + // it safe to assert that the total data set size is less than 2x the size. + assertThat(shardStats.getShardRouting().toString(), store.getTotalDataSetSize().getBytes(), lessThan(expectedSize * 2)); + + totalExpectedSize += expectedSize; + } + + // the extra segments_N file created for bootstrap new history and associate translog makes us unable to precisely assert this. + final StoreStats store = indicesStatsResponse.getTotal().getStore(); + assertThat(store.getTotalDataSetSize().getBytes(), greaterThanOrEqualTo(totalExpectedSize)); + assertThat(store.getTotalDataSetSize().getBytes(), lessThan(totalExpectedSize * 2)); + statsWatcherRunning.set(false); statsWatcher.join();