@@ -678,10 +678,10 @@ public void onFailure(Exception e) {
678
678
* @param rootBlobs Blobs at the repository root
679
679
* @return RepositoryData
680
680
*/
681
- private RepositoryData safeRepositoryData (long repositoryStateId , Map <String , BlobMetadata > rootBlobs ) throws IOException {
681
+ private RepositoryData safeRepositoryData (long repositoryStateId , Map <String , BlobMetadata > rootBlobs ) {
682
682
final long generation = latestGeneration (rootBlobs .keySet ());
683
683
final long genToLoad ;
684
- final Tuple < Long , BytesReference > cached ;
684
+ final CachedRepositoryData cached ;
685
685
if (bestEffortConsistency ) {
686
686
genToLoad = latestKnownRepoGen .updateAndGet (known -> Math .max (known , repositoryStateId ));
687
687
cached = null ;
@@ -700,8 +700,8 @@ private RepositoryData safeRepositoryData(long repositoryStateId, Map<String, Bl
700
700
throw new RepositoryException (metadata .name (), "concurrent modification of the index-N file, expected current generation [" +
701
701
repositoryStateId + "], actual current generation [" + genToLoad + "]" );
702
702
}
703
- if (cached != null && cached .v1 () == genToLoad ) {
704
- return repositoryDataFromCachedEntry ( cached );
703
+ if (cached != null && cached .generation () == genToLoad && cached . hasData () ) {
704
+ return cached . repositoryData ( );
705
705
}
706
706
return getRepositoryData (genToLoad );
707
707
}
@@ -1288,7 +1288,6 @@ public String startVerification() {
1288
1288
String seed = UUIDs .randomBase64UUID ();
1289
1289
byte [] testBytes = Strings .toUTF8Bytes (seed );
1290
1290
BlobContainer testContainer = blobStore ().blobContainer (basePath ().add (testBlobPrefix (seed )));
1291
- BytesArray bytes = new BytesArray (testBytes );
1292
1291
testContainer .writeBlobAtomic ("master.dat" , new BytesArray (testBytes ), true );
1293
1292
return seed ;
1294
1293
}
@@ -1314,20 +1313,62 @@ public void endVerification(String seed) {
1314
1313
private final AtomicLong latestKnownRepoGen = new AtomicLong (RepositoryData .UNKNOWN_REPO_GEN );
1315
1314
1316
1315
// Best effort cache of the latest known repository data and its generation, cached serialized as compressed json
1317
- private final AtomicReference <Tuple <Long , BytesReference >> latestKnownRepositoryData = new AtomicReference <>();
1316
+ private final AtomicReference <CachedRepositoryData > latestKnownRepositoryData =
1317
+ new AtomicReference <>(new CachedRepositoryData (RepositoryData .EMPTY_REPO_GEN , null ));
1318
+
1319
+ /**
1320
+ * Cached serialized repository data or placeholder to keep track of the fact that data for a generation was too large to be cached.
1321
+ */
1322
+ private static final class CachedRepositoryData {
1323
+
1324
+ private final long generation ;
1325
+
1326
+ @ Nullable
1327
+ private final BytesReference repositoryData ;
1328
+
1329
+ CachedRepositoryData (long generation , @ Nullable BytesReference repositoryData ) {
1330
+ this .generation = generation ;
1331
+ this .repositoryData = repositoryData ;
1332
+ }
1333
+
1334
+ long generation () {
1335
+ return generation ;
1336
+ }
1337
+
1338
+ boolean hasData () {
1339
+ return generation == RepositoryData .EMPTY_REPO_GEN || repositoryData != null ;
1340
+ }
1341
+
1342
+ @ Nullable
1343
+ RepositoryData repositoryData () {
1344
+ if (generation == RepositoryData .EMPTY_REPO_GEN ) {
1345
+ return RepositoryData .EMPTY ;
1346
+ }
1347
+ if (repositoryData == null ) {
1348
+ return null ;
1349
+ }
1350
+ try (InputStream input = CompressorFactory .COMPRESSOR .threadLocalInputStream (repositoryData .streamInput ())) {
1351
+ return RepositoryData .snapshotsFromXContent (
1352
+ XContentType .JSON .xContent ().createParser (NamedXContentRegistry .EMPTY , LoggingDeprecationHandler .INSTANCE , input ),
1353
+ generation , false );
1354
+ } catch (IOException e ) {
1355
+ throw new AssertionError ("no actual IO happens here" , e );
1356
+ }
1357
+ }
1358
+ }
1318
1359
1319
1360
@ Override
1320
1361
public void getRepositoryData (ActionListener <RepositoryData > listener ) {
1321
1362
if (latestKnownRepoGen .get () == RepositoryData .CORRUPTED_REPO_GEN ) {
1322
1363
listener .onFailure (corruptedStateException (null ));
1323
1364
return ;
1324
1365
}
1325
- final Tuple < Long , BytesReference > cached = latestKnownRepositoryData .get ();
1366
+ final CachedRepositoryData cached = latestKnownRepositoryData .get ();
1326
1367
// Fast path loading repository data directly from cache if we're in fully consistent mode and the cache matches up with
1327
1368
// the latest known repository generation
1328
- if (bestEffortConsistency == false && cached != null && cached . v1 () == latestKnownRepoGen .get ()) {
1369
+ if (bestEffortConsistency == false && cached . generation () == latestKnownRepoGen .get () && cached . hasData ()) {
1329
1370
try {
1330
- listener .onResponse (repositoryDataFromCachedEntry ( cached ));
1371
+ listener .onResponse (cached . repositoryData ( ));
1331
1372
} catch (Exception e ) {
1332
1373
listener .onFailure (e );
1333
1374
}
@@ -1357,26 +1398,28 @@ private void doGetRepositoryData(ActionListener<RepositoryData> listener) {
1357
1398
}
1358
1399
genToLoad = latestKnownRepoGen .updateAndGet (known -> Math .max (known , generation ));
1359
1400
if (genToLoad > generation ) {
1360
- logger .info ("Determined repository generation [" + generation
1361
- + "] from repository contents but correct generation must be at least [" + genToLoad + "]" );
1401
+ logger .info ("Determined repository generation [{}] from repository contents but correct generation must be at " +
1402
+ " least [{}]" , generation , genToLoad );
1362
1403
}
1363
1404
} else {
1364
1405
// We only rely on the generation tracked in #latestKnownRepoGen which is exclusively updated from the cluster state
1365
1406
genToLoad = latestKnownRepoGen .get ();
1366
1407
}
1367
1408
try {
1368
- final Tuple < Long , BytesReference > cached = latestKnownRepositoryData .get ();
1409
+ final CachedRepositoryData cached = latestKnownRepositoryData .get ();
1369
1410
final RepositoryData loaded ;
1370
1411
// Caching is not used with #bestEffortConsistency see docs on #cacheRepositoryData for details
1371
- if (bestEffortConsistency == false && cached != null && cached .v1 () == genToLoad ) {
1372
- loaded = repositoryDataFromCachedEntry ( cached );
1412
+ if (bestEffortConsistency == false && cached . generation () == genToLoad && cached .hasData () ) {
1413
+ loaded = cached . repositoryData ( );
1373
1414
} else {
1374
1415
loaded = getRepositoryData (genToLoad );
1375
- // We can cache serialized in the most recent version here without regard to the actual repository metadata version
1376
- // since we're only caching the information that we just wrote and thus won't accidentally cache any information that
1377
- // isn't safe
1378
- cacheRepositoryData (compressRepoDataForCache (BytesReference .bytes (
1379
- loaded .snapshotsToXContent (XContentFactory .jsonBuilder (), Version .CURRENT ))), genToLoad );
1416
+ if (cached == null || cached .generation () < genToLoad ) {
1417
+ // We can cache serialized in the most recent version here without regard to the actual repository metadata version
1418
+ // since we're only caching the information that we just wrote and thus won't accidentally cache any information
1419
+ // that isn't safe
1420
+ cacheRepositoryData (compressRepoDataForCache (BytesReference .bytes (
1421
+ loaded .snapshotsToXContent (XContentFactory .jsonBuilder (), Version .CURRENT ))), genToLoad );
1422
+ }
1380
1423
}
1381
1424
listener .onResponse (loaded );
1382
1425
return ;
@@ -1416,11 +1459,12 @@ private void doGetRepositoryData(ActionListener<RepositoryData> listener) {
1416
1459
* @param generation repository generation of the given repository data
1417
1460
*/
1418
1461
private void cacheRepositoryData (@ Nullable BytesReference serialized , long generation ) {
1462
+ assert generation >= 0 : "No need to cache abstract generations but attempted to cache [" + generation + "]" ;
1419
1463
latestKnownRepositoryData .updateAndGet (known -> {
1420
- if (known != null && known . v1 () > generation ) {
1464
+ if (known . generation () > generation ) {
1421
1465
return known ;
1422
1466
}
1423
- return serialized == null ? null : new Tuple <> (generation , serialized );
1467
+ return new CachedRepositoryData (generation , serialized );
1424
1468
});
1425
1469
}
1426
1470
@@ -1456,14 +1500,6 @@ private BytesReference compressRepoDataForCache(BytesReference uncompressed) {
1456
1500
}
1457
1501
}
1458
1502
1459
- private RepositoryData repositoryDataFromCachedEntry (Tuple <Long , BytesReference > cacheEntry ) throws IOException {
1460
- try (InputStream input = CompressorFactory .COMPRESSOR .threadLocalInputStream (cacheEntry .v2 ().streamInput ())) {
1461
- return RepositoryData .snapshotsFromXContent (
1462
- XContentType .JSON .xContent ().createParser (NamedXContentRegistry .EMPTY ,
1463
- LoggingDeprecationHandler .INSTANCE , input ), cacheEntry .v1 (), false );
1464
- }
1465
- }
1466
-
1467
1503
private RepositoryException corruptedStateException (@ Nullable Exception cause ) {
1468
1504
return new RepositoryException (metadata .name (),
1469
1505
"Could not read repository data because the contents of the repository do not match its " +
0 commit comments