Query migration to db done - Query persistence in cache is also done

This commit is contained in:
2026-08-01 16:08:52 +05:30
parent 934937feb0
commit 0dae53017d
26 changed files with 608 additions and 1564 deletions

File diff suppressed because one or more lines are too long

View File

@@ -173,16 +173,6 @@
<build>
<finalName>matrix</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<!-- Queries are supplied by the cloud query catalog at runtime. -->
<exclude>matrix/nimble/conf/nimble.qry</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@@ -16,11 +16,16 @@ public class OnPremRedisConfiguration {
@Value("${REDIS_HOST:192.168.0.111}") String host,
@Value("${REDIS_PORT:7901}") int port,
@Value("${REDIS_PASSWORD:}") String password,
@Value("${REDIS_DATABASE:1}") int database,
@Value("${REDIS_SSL:false}") boolean ssl,
@Value("${REDIS_CONNECT_TIMEOUT_SECONDS:3}") long connectTimeoutSeconds) {
if (database < 0) {
throw new IllegalArgumentException("REDIS_DATABASE must be zero or greater");
}
RedisURI.Builder uri = RedisURI.builder()
.withHost(host)
.withPort(port)
.withDatabase(database)
.withSsl(ssl)
.withTimeout(Duration.ofSeconds(connectTimeoutSeconds));
if (password != null && !password.isBlank()) {

View File

@@ -11,7 +11,7 @@ public final class CloudQuerySource implements QuerySource {
}
@Override
public String fetch(String queryId) {
public String fetch(int queryId) {
return client.fetchQuery(queryId)
.map(response -> response.query())
.blockOptional()
@@ -20,4 +20,3 @@ public final class CloudQuerySource implements QuerySource {
"Cloud query was empty: " + queryId));
}
}

View File

@@ -2,10 +2,5 @@ package matrix.nimble.query;
public interface QueryProvider {
String getQuery(String queryId);
default String getQuery(int queryId) {
return getQuery("Query" + queryId);
}
String getQuery(int queryId);
}

View File

@@ -3,6 +3,5 @@ package matrix.nimble.query;
@FunctionalInterface
public interface QuerySource {
String fetch(String queryId);
String fetch(int queryId);
}

View File

@@ -30,27 +30,27 @@ public final class RedisCachingQueryProvider implements QueryProvider {
}
@Override
public String getQuery(String queryId) {
String normalized = normalize(queryId);
Optional<String> cached = cached(normalized);
public String getQuery(int queryId) {
String cacheKey = cacheKey(queryId);
Optional<String> cached = cached(cacheKey);
if (cached.isPresent()) {
return cached.get();
}
synchronized (lock(normalized)) {
cached = cached(normalized);
synchronized (lock(cacheKey)) {
cached = cached(cacheKey);
if (cached.isPresent()) {
return cached.get();
}
try {
String query = cloudSource.fetch(normalized);
cache.put(normalized, cipher.encrypt(normalized, query), QUERY_TTL);
String query = cloudSource.fetch(queryId);
cache.put(cacheKey, cipher.encrypt(cacheKey, query), QUERY_TTL);
return query;
} catch (QueryProviderException exception) {
throw exception;
} catch (RuntimeException exception) {
throw new QueryProviderException(
"Unable to retrieve query: " + normalized, exception);
"Unable to retrieve query: " + queryId, exception);
}
}
}
@@ -72,10 +72,10 @@ public final class RedisCachingQueryProvider implements QueryProvider {
return locks[(queryId.hashCode() & Integer.MAX_VALUE) % locks.length];
}
private String normalize(String queryId) {
if (queryId == null || !queryId.matches("^[A-Za-z0-9._-]+$")) {
private String cacheKey(int queryId) {
if (queryId <= 0) {
throw new IllegalArgumentException("Invalid query ID");
}
return queryId;
return Integer.toString(queryId);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -12,6 +12,6 @@ class FileFunctionsQueryCacheTest {
void delegatesLegacyQueryLookupToQueryProvider() throws Exception {
QueryProviders.install(queryId -> "provided:" + queryId);
FileFunctions files = new FileFunctions("TEST");
assertEquals("provided:Query3", files.GetQuery(3));
assertEquals("provided:3", files.GetQuery(3));
}
}

View File

@@ -15,13 +15,13 @@ class AesGcmQueryCipherTest {
Arrays.fill(key, (byte) 7);
AesGcmQueryCipher cipher = new AesGcmQueryCipher(key);
String encrypted = cipher.encrypt("Query3", "select * from portfolio");
String encrypted = cipher.encrypt("3", "select * from portfolio");
assertNotEquals("select * from portfolio", encrypted);
assertTrue(encrypted.startsWith("v1."));
org.junit.jupiter.api.Assertions.assertEquals(
"select * from portfolio", cipher.decrypt("Query3", encrypted));
"select * from portfolio", cipher.decrypt("3", encrypted));
assertThrows(IllegalStateException.class,
() -> cipher.decrypt("Query4", encrypted));
() -> cipher.decrypt("4", encrypted));
}
}

View File

@@ -27,13 +27,13 @@ class RedisCachingQueryProviderTest {
},
cipher);
assertEquals("select!C0L!select 1", provider.getQuery("Query10"));
assertEquals("select!C0L!select 1", provider.getQuery("Query10"));
assertEquals("select!C0L!select 1", provider.getQuery(10));
assertEquals("select!C0L!select 1", provider.getQuery(10));
assertEquals(1, cloudCalls.get());
assertEquals(Duration.ofHours(3), cache.ttl.get());
org.junit.jupiter.api.Assertions.assertNotEquals(
"select!C0L!select 1", cache.values.get("Query10"));
"select!C0L!select 1", cache.values.get("10"));
}
@Test
@@ -55,7 +55,7 @@ class RedisCachingQueryProviderTest {
var executor = Executors.newFixedThreadPool(8);
try {
for (int index = 0; index < 20; index++) {
executor.submit(() -> provider.getQuery("Query20"));
executor.submit(() -> provider.getQuery(20));
}
} finally {
executor.shutdown();