Skip to content

Commit 7ae572b

Browse files
committed
Disable nagative cache in VirtualTableInfoManager
1 parent 20f476d commit 7ae572b

File tree

5 files changed

+58
-59
lines changed

5 files changed

+58
-59
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ subprojects {
4343
alloyDbJdbcConnectorVersion = '1.2.8'
4444
picocliVersion = '4.7.7'
4545
commonsTextVersion = '1.14.0'
46+
caffeineVersion = '2.9.3'
4647
junitVersion = '5.14.1'
4748
commonsLangVersion = '3.20.0'
4849
assertjVersion = '3.27.6'

core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ dependencies {
194194
exclude group: 'org.slf4j', module: 'slf4j-api'
195195
}
196196
implementation "org.apache.commons:commons-text:${commonsTextVersion}"
197+
implementation "com.github.ben-manes.caffeine:caffeine:${caffeineVersion}"
197198
testImplementation platform("org.junit:junit-bom:${junitVersion}")
198199
testImplementation 'org.junit.jupiter:junit-jupiter'
199200
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

core/src/main/java/com/scalar/db/common/TableMetadataManager.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.scalar.db.common;
22

3-
import com.google.common.annotations.VisibleForTesting;
43
import com.google.common.cache.CacheBuilder;
54
import com.google.common.cache.CacheLoader;
65
import com.google.common.cache.LoadingCache;
@@ -14,7 +13,6 @@
1413
import java.util.Optional;
1514
import java.util.concurrent.TimeUnit;
1615
import javax.annotation.Nonnull;
17-
import javax.annotation.Nullable;
1816
import javax.annotation.concurrent.ThreadSafe;
1917

2018
/** A class that manages and caches table metadata */
@@ -54,7 +52,6 @@ public Optional<TableMetadata> load(@Nonnull TableKey key) throws Exception {
5452
* @return a table metadata. null if the table is not found.
5553
* @throws ExecutionException if the operation fails
5654
*/
57-
@Nullable
5855
public TableMetadata getTableMetadata(Operation operation) throws ExecutionException {
5956
if (!operation.forNamespace().isPresent() || !operation.forTable().isPresent()) {
6057
throw new IllegalArgumentException(
@@ -64,14 +61,13 @@ public TableMetadata getTableMetadata(Operation operation) throws ExecutionExcep
6461
}
6562

6663
/**
67-
* Returns a table metadata corresponding to the specified namespace and table.
64+
* Returns a table metadata corresponding to the specified operation.
6865
*
6966
* @param namespace a namespace to retrieve
7067
* @param table a table to retrieve
7168
* @return a table metadata. null if the table is not found.
7269
* @throws ExecutionException if the operation fails
7370
*/
74-
@Nullable
7571
public TableMetadata getTableMetadata(String namespace, String table) throws ExecutionException {
7672
try {
7773
TableKey key = new TableKey(namespace, table);
@@ -80,12 +76,11 @@ public TableMetadata getTableMetadata(String namespace, String table) throws Exe
8076
throw new ExecutionException(
8177
CoreError.GETTING_TABLE_METADATA_FAILED.buildMessage(
8278
ScalarDbUtils.getFullTableName(namespace, table)),
83-
e.getCause());
79+
e);
8480
}
8581
}
8682

87-
@VisibleForTesting
88-
static class TableKey {
83+
public static class TableKey {
8984
public final String namespace;
9085
public final String table;
9186

core/src/main/java/com/scalar/db/common/VirtualTableInfoManager.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,32 @@
11
package com.scalar.db.common;
22

3+
import com.github.benmanes.caffeine.cache.Caffeine;
4+
import com.github.benmanes.caffeine.cache.LoadingCache;
35
import com.google.common.annotations.VisibleForTesting;
4-
import com.google.common.cache.CacheBuilder;
5-
import com.google.common.cache.CacheLoader;
6-
import com.google.common.cache.LoadingCache;
76
import com.scalar.db.api.DistributedStorageAdmin;
87
import com.scalar.db.api.Operation;
98
import com.scalar.db.api.VirtualTableInfo;
109
import com.scalar.db.exception.storage.ExecutionException;
1110
import com.scalar.db.util.ScalarDbUtils;
1211
import java.util.Objects;
13-
import java.util.Optional;
12+
import java.util.concurrent.CompletionException;
1413
import java.util.concurrent.TimeUnit;
15-
import javax.annotation.Nonnull;
1614
import javax.annotation.Nullable;
1715
import javax.annotation.concurrent.ThreadSafe;
1816

1917
/** A class that manages and caches virtual table information */
2018
@ThreadSafe
2119
public class VirtualTableInfoManager {
2220

23-
private final LoadingCache<TableKey, Optional<VirtualTableInfo>> virtualTableInfoCache;
21+
private final LoadingCache<TableKey, VirtualTableInfo> virtualTableInfoCache;
2422

2523
public VirtualTableInfoManager(DistributedStorageAdmin admin, long cacheExpirationTimeSecs) {
26-
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
24+
Caffeine<Object, Object> builder = Caffeine.newBuilder();
2725
if (cacheExpirationTimeSecs >= 0) {
2826
builder.expireAfterWrite(cacheExpirationTimeSecs, TimeUnit.SECONDS);
2927
}
3028
virtualTableInfoCache =
31-
builder.build(
32-
new CacheLoader<TableKey, Optional<VirtualTableInfo>>() {
33-
@Nonnull
34-
@Override
35-
public Optional<VirtualTableInfo> load(@Nonnull TableKey key) throws Exception {
36-
return admin.getVirtualTableInfo(key.namespace, key.table);
37-
}
38-
});
29+
builder.build(key -> admin.getVirtualTableInfo(key.namespace, key.table).orElse(null));
3930
}
4031

4132
/**
@@ -69,13 +60,8 @@ public VirtualTableInfo getVirtualTableInfo(String namespace, String table)
6960
throws ExecutionException {
7061
try {
7162
TableKey key = new TableKey(namespace, table);
72-
return virtualTableInfoCache.get(key).orElse(null);
73-
} catch (java.util.concurrent.ExecutionException
74-
| com.google.common.util.concurrent.UncheckedExecutionException e) {
75-
if (e.getCause() instanceof RuntimeException) {
76-
throw (RuntimeException) e.getCause();
77-
}
78-
63+
return virtualTableInfoCache.get(key);
64+
} catch (CompletionException e) {
7965
throw new ExecutionException(
8066
CoreError.GETTING_VIRTUAL_TABLE_INFO_FAILED.buildMessage(
8167
ScalarDbUtils.getFullTableName(namespace, table)),

core/src/test/java/com/scalar/db/common/VirtualTableInfoManagerTest.java

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,35 +120,6 @@ public void getVirtualTableInfo_VirtualTableDoesNotExist_ShouldReturnNull() thro
120120
verify(admin).getVirtualTableInfo("ns", "table");
121121
}
122122

123-
@Test
124-
public void getVirtualTableInfo_AdminThrowsRuntimeException_ShouldThrowRuntimeException()
125-
throws Exception {
126-
// Arrange
127-
manager = new VirtualTableInfoManager(admin, -1);
128-
when(admin.getVirtualTableInfo("ns", "table"))
129-
.thenThrow(new IllegalArgumentException("Table does not exist"));
130-
131-
// Act Assert
132-
assertThatThrownBy(() -> manager.getVirtualTableInfo("ns", "table"))
133-
.isInstanceOf(IllegalArgumentException.class)
134-
.hasMessageContaining("Table does not exist");
135-
}
136-
137-
@Test
138-
public void getVirtualTableInfo_AdminThrowsExecutionException_ShouldWrapInExecutionException()
139-
throws Exception {
140-
// Arrange
141-
manager = new VirtualTableInfoManager(admin, -1);
142-
when(admin.getVirtualTableInfo("ns", "table"))
143-
.thenThrow(new ExecutionException("Storage execution error"));
144-
145-
// Act Assert
146-
assertThatThrownBy(() -> manager.getVirtualTableInfo("ns", "table"))
147-
.isInstanceOf(ExecutionException.class)
148-
.hasMessageContaining("Getting the virtual table information failed")
149-
.hasMessageContaining("ns.table");
150-
}
151-
152123
@Test
153124
public void getVirtualTableInfo_CalledMultipleTimes_ShouldUseCache() throws Exception {
154125
// Arrange
@@ -185,6 +156,51 @@ public void getVirtualTableInfo_WithCacheExpiration_ShouldExpireCache() throws E
185156
verify(admin, times(2)).getVirtualTableInfo("ns", "table");
186157
}
187158

159+
@Test
160+
public void getVirtualTableInfo_VirtualTableDoesNotExist_ShouldNotCacheNullResult()
161+
throws Exception {
162+
// Arrange
163+
manager = new VirtualTableInfoManager(admin, -1);
164+
when(admin.getVirtualTableInfo("ns", "table")).thenReturn(Optional.empty());
165+
166+
// Act
167+
manager.getVirtualTableInfo("ns", "table");
168+
manager.getVirtualTableInfo("ns", "table");
169+
manager.getVirtualTableInfo("ns", "table");
170+
171+
// Assert - admin should be called multiple times because null is not cached
172+
verify(admin, times(3)).getVirtualTableInfo("ns", "table");
173+
}
174+
175+
@Test
176+
public void getVirtualTableInfo_AdminThrowsRuntimeException_ShouldThrowRuntimeException()
177+
throws Exception {
178+
// Arrange
179+
manager = new VirtualTableInfoManager(admin, -1);
180+
when(admin.getVirtualTableInfo("ns", "table"))
181+
.thenThrow(new IllegalArgumentException("Table does not exist"));
182+
183+
// Act Assert
184+
assertThatThrownBy(() -> manager.getVirtualTableInfo("ns", "table"))
185+
.isInstanceOf(IllegalArgumentException.class)
186+
.hasMessageContaining("Table does not exist");
187+
}
188+
189+
@Test
190+
public void getVirtualTableInfo_AdminThrowsExecutionException_ShouldWrapInExecutionException()
191+
throws Exception {
192+
// Arrange
193+
manager = new VirtualTableInfoManager(admin, -1);
194+
when(admin.getVirtualTableInfo("ns", "table"))
195+
.thenThrow(new ExecutionException("Storage execution error"));
196+
197+
// Act Assert
198+
assertThatThrownBy(() -> manager.getVirtualTableInfo("ns", "table"))
199+
.isInstanceOf(ExecutionException.class)
200+
.hasMessageContaining("Getting the virtual table information failed")
201+
.hasMessageContaining("ns.table");
202+
}
203+
188204
private VirtualTableInfo createVirtualTableInfo() {
189205
return new VirtualTableInfo() {
190206
@Override

0 commit comments

Comments
 (0)