Skip to content

Commit a6a8e7e

Browse files
Fix performance bug in MostRecentProvider
1 parent 57f923d commit a6a8e7e

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/MostRecentProvider.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,25 @@ public EncryptionMaterials getEncryptionMaterials(EncryptionContext context) {
7070
final long currentVersion;
7171
final EncryptionMaterialsProvider currentProvider;
7272
if (newVersion < 0) {
73+
// First version of the material, so we want to allow creation
7374
currentVersion = 0;
7475
currentProvider = keystore.getOrCreate(materialName, currentVersion);
75-
s = new State(currentProvider, currentVersion);
76-
state.set(s);
76+
cache.add(Long.toString(currentVersion), currentProvider);
7777
} else if (newVersion != s.currentVersion) {
78+
// We're retrieving an existing version, so we avoid the creation
79+
// flow as it is slower
7880
currentVersion = newVersion;
7981
currentProvider = keystore.getProvider(materialName, currentVersion);
8082
cache.add(Long.toString(currentVersion), currentProvider);
81-
s = new State(currentProvider, currentVersion);
82-
state.set(s);
83+
} else {
84+
// Our version hasn't changed, so we'll just re-use the existing
85+
// provider to avoid the overhead of retrieving and building a new one
86+
currentVersion = newVersion;
87+
currentProvider = s.provider;
88+
// There is no need to add this to the cache as it's already there
8389
}
90+
s = new State(currentProvider, currentVersion);
91+
state.set(s);
8492

8593
return s.provider.getEncryptionMaterials(context);
8694
} finally {

src/test/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/MostRecentProviderTests.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void singleMaterial() throws InterruptedException {
120120

121121
@Test
122122
public void singleMaterialWithRefresh() throws InterruptedException {
123-
final MostRecentProvider prov = new MostRecentProvider(store, MATERIAL_NAME, 100);
123+
final MostRecentProvider prov = new MostRecentProvider(store, MATERIAL_NAME, 500);
124124
assertNull(methodCalls.get("putItem"));
125125
final EncryptionMaterials eMat1 = prov.getEncryptionMaterials(ctx);
126126
// It's a new provider, so we see a single putItem
@@ -136,10 +136,25 @@ public void singleMaterialWithRefresh() throws InterruptedException {
136136
assertEquals(1, (int) methodCalls.get("query")); // To find current version
137137
assertEquals(1, (int) methodCalls.get("getItem"));
138138
assertEquals(0, store.getVersionFromMaterialDescription(eMat3.getMaterialDescription()));
139+
prov.refresh();
139140

140141
assertEquals(eMat1.getSigningKey(), eMat2.getSigningKey());
141142
assertEquals(eMat1.getSigningKey(), eMat3.getSigningKey());
142143

144+
// Ensure that after cache refresh we only get one more hit as opposed to multiple
145+
prov.getEncryptionMaterials(ctx);
146+
Thread.sleep(700);
147+
// Force refresh
148+
prov.getEncryptionMaterials(ctx);
149+
methodCalls.clear();
150+
// Check to ensure no more hits
151+
assertEquals(eMat1.getSigningKey(), prov.getEncryptionMaterials(ctx).getSigningKey());
152+
assertEquals(eMat1.getSigningKey(), prov.getEncryptionMaterials(ctx).getSigningKey());
153+
assertEquals(eMat1.getSigningKey(), prov.getEncryptionMaterials(ctx).getSigningKey());
154+
assertEquals(eMat1.getSigningKey(), prov.getEncryptionMaterials(ctx).getSigningKey());
155+
assertEquals(eMat1.getSigningKey(), prov.getEncryptionMaterials(ctx).getSigningKey());
156+
assertTrue(methodCalls.isEmpty());
157+
143158
// Ensure we can decrypt all of them without hitting ddb more than the minimum
144159
final MostRecentProvider prov2 = new MostRecentProvider(store, MATERIAL_NAME, 500);
145160
final DecryptionMaterials dMat1 = prov2.getDecryptionMaterials(ctx(eMat1));

0 commit comments

Comments
 (0)