|
16 | 16 | import org.apache.lucene.document.StringField; |
17 | 17 | import org.apache.lucene.document.TextField; |
18 | 18 | import org.apache.lucene.index.Fields; |
| 19 | +import org.apache.lucene.index.IndexCommit; |
19 | 20 | import org.apache.lucene.index.IndexWriter; |
20 | 21 | import org.apache.lucene.index.IndexWriterConfig; |
21 | 22 | import org.apache.lucene.index.SegmentInfos; |
22 | 23 | import org.apache.lucene.index.StandardDirectoryReader; |
| 24 | +import org.apache.lucene.store.Directory; |
23 | 25 | import org.apache.lucene.tests.util.TestUtil; |
24 | 26 | import org.apache.lucene.util.BytesRef; |
25 | 27 | import org.opensearch.action.admin.cluster.stats.ClusterStatsResponse; |
26 | 28 | import org.opensearch.action.admin.indices.alias.Alias; |
27 | 29 | import org.opensearch.action.admin.indices.flush.FlushRequest; |
| 30 | +import org.opensearch.action.admin.indices.forcemerge.ForceMergeRequest; |
28 | 31 | import org.opensearch.action.admin.indices.forcemerge.ForceMergeResponse; |
29 | 32 | import org.opensearch.action.admin.indices.stats.IndicesStatsRequest; |
30 | 33 | import org.opensearch.action.admin.indices.stats.IndicesStatsResponse; |
|
54 | 57 | import org.opensearch.cluster.routing.ShardRoutingState; |
55 | 58 | import org.opensearch.cluster.routing.allocation.command.CancelAllocationCommand; |
56 | 59 | import org.opensearch.common.action.ActionFuture; |
| 60 | +import org.opensearch.common.concurrent.GatedCloseable; |
57 | 61 | import org.opensearch.common.lease.Releasable; |
58 | 62 | import org.opensearch.common.lucene.index.OpenSearchDirectoryReader; |
59 | 63 | import org.opensearch.common.settings.Settings; |
@@ -136,6 +140,109 @@ private static String indexOrAlias() { |
136 | 140 | return randomBoolean() ? INDEX_NAME : "alias"; |
137 | 141 | } |
138 | 142 |
|
| 143 | + public void testAcquireLastIndexCommit() throws Exception { |
| 144 | + final String primaryNode = internalCluster().startDataOnlyNode(); |
| 145 | + createIndex(INDEX_NAME); |
| 146 | + ensureYellowAndNoInitializingShards(INDEX_NAME); |
| 147 | + final String replicaNode = internalCluster().startDataOnlyNode(); |
| 148 | + ensureGreen(INDEX_NAME); |
| 149 | + |
| 150 | + // generate _0.si |
| 151 | + client().prepareIndex(INDEX_NAME) |
| 152 | + .setId(String.valueOf(1)) |
| 153 | + .setSource("foo", "bar") |
| 154 | + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) |
| 155 | + .get(); |
| 156 | + |
| 157 | + // generate _1.si |
| 158 | + client().prepareIndex(INDEX_NAME) |
| 159 | + .setId(String.valueOf(2)) |
| 160 | + .setSource("foo2", "bar2") |
| 161 | + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) |
| 162 | + .get(); |
| 163 | + |
| 164 | + waitForSearchableDocs(2, primaryNode, replicaNode); |
| 165 | + |
| 166 | + // primary and replica generate index commit |
| 167 | + IndexShard primaryShard = getIndexShard(primaryNode, INDEX_NAME); |
| 168 | + primaryShard.flush(new FlushRequest(INDEX_NAME)); |
| 169 | + IndexShard replicaShard = getIndexShard(replicaNode, INDEX_NAME); |
| 170 | + replicaShard.flush(new FlushRequest(INDEX_NAME)); |
| 171 | + |
| 172 | + logger.info("primary {} acquire last IndexCommit", primaryShard.shardId()); |
| 173 | + GatedCloseable<IndexCommit> primaryIndexCommit = primaryShard.acquireLastIndexCommit(false); |
| 174 | + |
| 175 | + logger.info("replica {} acquire last IndexCommit", replicaShard.shardId()); |
| 176 | + GatedCloseable<IndexCommit> replicaIndexCommit = replicaShard.acquireLastIndexCommit(false); |
| 177 | + |
| 178 | + logger.info("Verify that before merge, primary and replica contain _0.si and _1.si"); |
| 179 | + Directory primaryDirectory = primaryShard.store().directory(); |
| 180 | + Set<String> primaryFilesBeforeMerge = Sets.newHashSet(primaryDirectory.listAll()); |
| 181 | + logger.info("primaryFilesBeforeMerge {}: {}", primaryFilesBeforeMerge.size(), primaryFilesBeforeMerge); |
| 182 | + assertTrue( |
| 183 | + primaryFilesBeforeMerge.stream().anyMatch(s -> s.startsWith("_0")) |
| 184 | + && primaryFilesBeforeMerge.stream().anyMatch(s -> s.startsWith("_1")) |
| 185 | + ); |
| 186 | + |
| 187 | + Directory replicaDirectory = replicaShard.store().directory(); |
| 188 | + Set<String> replicaFilesBeforeMerge = Sets.newHashSet(replicaDirectory.listAll()); |
| 189 | + logger.info("replicaFilesBeforeMerge {}: {}", replicaFilesBeforeMerge.size(), replicaFilesBeforeMerge); |
| 190 | + assertTrue( |
| 191 | + replicaFilesBeforeMerge.stream().anyMatch(s -> s.startsWith("_0")) |
| 192 | + && replicaFilesBeforeMerge.stream().anyMatch(s -> s.startsWith("_1")) |
| 193 | + ); |
| 194 | + |
| 195 | + // generate _2.si |
| 196 | + client().admin().indices().forceMerge(new ForceMergeRequest(INDEX_NAME).maxNumSegments(1)); |
| 197 | + waitForSegmentCount(INDEX_NAME, 1, logger); |
| 198 | + primaryShard.flush(new FlushRequest(INDEX_NAME)); |
| 199 | + replicaShard.flush(new FlushRequest(INDEX_NAME)); |
| 200 | + |
| 201 | + logger.info("Verify that after merge, primary and replica contain _0.si, _1.si and _2.si"); |
| 202 | + Set<String> primaryFilesAfterMerge = Sets.newHashSet(primaryDirectory.listAll()); |
| 203 | + logger.info("primaryFilesAfterMerge {}: {}", primaryFilesAfterMerge.size(), primaryFilesAfterMerge); |
| 204 | + assertTrue( |
| 205 | + primaryFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_0")) |
| 206 | + && primaryFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_1")) |
| 207 | + && primaryFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_2")) |
| 208 | + ); |
| 209 | + |
| 210 | + Set<String> replicaFilesAfterMerge = Sets.newHashSet(replicaDirectory.listAll()); |
| 211 | + logger.info("replicaFilesAfterMerge {}: {}", replicaFilesAfterMerge.size(), replicaFilesAfterMerge); |
| 212 | + assertTrue( |
| 213 | + replicaFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_0")) |
| 214 | + && replicaFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_1")) |
| 215 | + && replicaFilesAfterMerge.stream().anyMatch(s -> s.startsWith("_2")) |
| 216 | + ); |
| 217 | + |
| 218 | + logger.info("Verify that after close index commit, primary and replica only contain _2.si"); |
| 219 | + primaryIndexCommit.close(); |
| 220 | + Set<String> primaryFilesAfterIndexCommitClose = Sets.newHashSet(primaryDirectory.listAll()); |
| 221 | + logger.info( |
| 222 | + "primaryFilesAfterIndexCommitClose {}: {}", |
| 223 | + primaryFilesAfterIndexCommitClose.size(), |
| 224 | + primaryFilesAfterIndexCommitClose |
| 225 | + ); |
| 226 | + assertTrue( |
| 227 | + primaryFilesAfterIndexCommitClose.stream().noneMatch(s -> s.startsWith("_0")) |
| 228 | + && primaryFilesAfterIndexCommitClose.stream().noneMatch(s -> s.startsWith("_1")) |
| 229 | + && primaryFilesAfterIndexCommitClose.stream().anyMatch(s -> s.startsWith("_2")) |
| 230 | + ); |
| 231 | + |
| 232 | + replicaIndexCommit.close(); |
| 233 | + Set<String> replicaFilesAfterIndexCommitClose = Sets.newHashSet(replicaDirectory.listAll()); |
| 234 | + logger.info( |
| 235 | + "replicaFilesAfterIndexCommitClose {}: {}", |
| 236 | + replicaFilesAfterIndexCommitClose.size(), |
| 237 | + replicaFilesAfterIndexCommitClose |
| 238 | + ); |
| 239 | + assertTrue( |
| 240 | + replicaFilesAfterIndexCommitClose.stream().noneMatch(s -> s.startsWith("_0")) |
| 241 | + && replicaFilesAfterIndexCommitClose.stream().noneMatch(s -> s.startsWith("_1")) |
| 242 | + && replicaFilesAfterIndexCommitClose.stream().anyMatch(s -> s.startsWith("_2")) |
| 243 | + ); |
| 244 | + } |
| 245 | + |
139 | 246 | public void testRetryPublishCheckPoint() throws Exception { |
140 | 247 | // Reproduce the case where the replica shard cannot synchronize data from the primary shard when there is a network exception. |
141 | 248 | // Test update of configuration PublishCheckpointAction#PUBLISH_CHECK_POINT_RETRY_TIMEOUT. |
|
0 commit comments