|
54 | 54 | import org.elasticsearch.telemetry.InstrumentType; |
55 | 55 | import org.elasticsearch.telemetry.Measurement; |
56 | 56 | import org.elasticsearch.telemetry.RecordingMeterRegistry; |
| 57 | +import org.elasticsearch.test.ESTestCase; |
57 | 58 | import org.elasticsearch.watcher.ResourceWatcherService; |
58 | 59 | import org.hamcrest.Matcher; |
59 | 60 | import org.junit.After; |
@@ -162,6 +163,16 @@ protected BlobContainer createBlobContainer( |
162 | 163 | final @Nullable TimeValue readTimeout, |
163 | 164 | final @Nullable Boolean disableChunkedEncoding, |
164 | 165 | final @Nullable ByteSizeValue bufferSize |
| 166 | + ) { |
| 167 | + return createBlobContainer(maxRetries, readTimeout, disableChunkedEncoding, bufferSize, null); |
| 168 | + } |
| 169 | + |
| 170 | + protected BlobContainer createBlobContainer( |
| 171 | + final @Nullable Integer maxRetries, |
| 172 | + final @Nullable TimeValue readTimeout, |
| 173 | + final @Nullable Boolean disableChunkedEncoding, |
| 174 | + final @Nullable ByteSizeValue bufferSize, |
| 175 | + final @Nullable Integer maxBulkDeletes |
165 | 176 | ) { |
166 | 177 | final Settings.Builder clientSettings = Settings.builder(); |
167 | 178 | final String clientName = randomAlphaOfLength(5).toLowerCase(Locale.ROOT); |
@@ -192,14 +203,13 @@ protected BlobContainer createBlobContainer( |
192 | 203 | clientSettings.setSecureSettings(secureSettings); |
193 | 204 | service.refreshAndClearCache(S3ClientSettings.load(clientSettings.build())); |
194 | 205 |
|
195 | | - final RepositoryMetadata repositoryMetadata = new RepositoryMetadata( |
196 | | - "repository", |
197 | | - S3Repository.TYPE, |
198 | | - Settings.builder() |
199 | | - .put(S3Repository.CLIENT_NAME.getKey(), clientName) |
200 | | - .put(S3Repository.GET_REGISTER_RETRY_DELAY.getKey(), TimeValue.ZERO) |
201 | | - .build() |
202 | | - ); |
| 206 | + final var repositorySettings = Settings.builder() |
| 207 | + .put(S3Repository.CLIENT_NAME.getKey(), clientName) |
| 208 | + .put(S3Repository.GET_REGISTER_RETRY_DELAY.getKey(), TimeValue.ZERO); |
| 209 | + if (maxBulkDeletes != null) { |
| 210 | + repositorySettings.put(S3Repository.DELETION_BATCH_SIZE_SETTING.getKey(), maxBulkDeletes); |
| 211 | + } |
| 212 | + final RepositoryMetadata repositoryMetadata = new RepositoryMetadata("repository", S3Repository.TYPE, repositorySettings.build()); |
203 | 213 |
|
204 | 214 | final S3BlobStore s3BlobStore = new S3BlobStore( |
205 | 215 | service, |
@@ -1073,6 +1083,38 @@ interface FailingHandlerFactory { |
1073 | 1083 | } |
1074 | 1084 | } |
1075 | 1085 |
|
| 1086 | + public void testSuppressedDeletionErrorsAreCapped() { |
| 1087 | + final TimeValue readTimeout = TimeValue.timeValueMillis(randomIntBetween(100, 500)); |
| 1088 | + int maxBulkDeleteSize = randomIntBetween(1, 10); |
| 1089 | + final BlobContainer blobContainer = createBlobContainer(1, readTimeout, true, null, maxBulkDeleteSize); |
| 1090 | + httpServer.createContext("/", exchange -> { |
| 1091 | + if (exchange.getRequestMethod().equals("POST") && exchange.getRequestURI().toString().startsWith("/bucket/?delete")) { |
| 1092 | + exchange.sendResponseHeaders( |
| 1093 | + randomFrom( |
| 1094 | + HttpStatus.SC_INTERNAL_SERVER_ERROR, |
| 1095 | + HttpStatus.SC_BAD_GATEWAY, |
| 1096 | + HttpStatus.SC_SERVICE_UNAVAILABLE, |
| 1097 | + HttpStatus.SC_GATEWAY_TIMEOUT, |
| 1098 | + HttpStatus.SC_NOT_FOUND, |
| 1099 | + HttpStatus.SC_UNAUTHORIZED |
| 1100 | + ), |
| 1101 | + -1 |
| 1102 | + ); |
| 1103 | + exchange.close(); |
| 1104 | + } else { |
| 1105 | + fail("expected only deletions"); |
| 1106 | + } |
| 1107 | + }); |
| 1108 | + try { |
| 1109 | + var maxNoOfDeletions = 2 * S3BlobStore.MAX_DELETE_EXCEPTIONS; |
| 1110 | + var blobs = randomList(1, maxNoOfDeletions * maxBulkDeleteSize, ESTestCase::randomIdentifier); |
| 1111 | + blobContainer.deleteBlobsIgnoringIfNotExists(randomPurpose(), blobs.iterator()); |
| 1112 | + fail("deletion should not succeed"); |
| 1113 | + } catch (IOException e) { |
| 1114 | + assertThat(e.getCause().getSuppressed().length, lessThan(S3BlobStore.MAX_DELETE_EXCEPTIONS)); |
| 1115 | + } |
| 1116 | + } |
| 1117 | + |
1076 | 1118 | @Override |
1077 | 1119 | protected Matcher<Integer> getMaxRetriesMatcher(int maxRetries) { |
1078 | 1120 | // some attempts make meaningful progress and do not count towards the max retry limit |
|
0 commit comments