Skip to content
Snippets Groups Projects
Commit f3ab173f authored by Henrik tom Wörden's avatar Henrik tom Wörden
Browse files

Merge branch 'dev' into f-fix-pipeline

parents b515c60c 0d2227e7
No related branches found
No related tags found
1 merge request!3F fix pipeline
This commit is part of merge request !3. Comments created here will be created in the context of that merge request.
...@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ...@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
* `ETag` property for the query. The `ETag` is assigned to the query cache
each time the cache is cleared (currently whenever the server state is being
updated, i.e. the stored entities change).
This can be used to debug the query cache and also allows a client
to determine whether the server's state has changed between queries.
* Basic caching for queries. The caching is enabled by default and can be * Basic caching for queries. The caching is enabled by default and can be
controlled by the usual "cache" flag. controlled by the usual "cache" flag.
......
...@@ -39,6 +39,7 @@ import java.util.LinkedList; ...@@ -39,6 +39,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.commons.jcs.access.behavior.ICacheAccess; import org.apache.commons.jcs.access.behavior.ICacheAccess;
...@@ -238,6 +239,14 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -238,6 +239,14 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
*/ */
private boolean cachable = true; private boolean cachable = true;
/**
* Tags the query cache and is renewed each time the cache is being cleared, i.e. each time the
* database is being updated.
*
* <p>As the name suggests, the idea is similar to the ETag header of the HTTP protocol.
*/
private static String cacheETag = UUID.randomUUID().toString();
public Type getType() { public Type getType() {
return this.type; return this.type;
} }
...@@ -668,6 +677,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -668,6 +677,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
/** Remove all cached queries from the cache. */ /** Remove all cached queries from the cache. */
public static void clearCache() { public static void clearCache() {
cacheETag = UUID.randomUUID().toString();
cache.clear(); cache.clear();
} }
...@@ -678,10 +688,12 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -678,10 +688,12 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
* @param resultSet * @param resultSet
*/ */
private void setCache(String key, List<IdVersionPair> resultSet) { private void setCache(String key, List<IdVersionPair> resultSet) {
if (resultSet instanceof Serializable) { synchronized (cache) {
cache.put(key, (Serializable) resultSet); if (resultSet instanceof Serializable) {
} else { cache.put(key, (Serializable) resultSet);
cache.put(key, new ArrayList<>(resultSet)); } else {
cache.put(key, new ArrayList<>(resultSet));
}
} }
} }
...@@ -859,6 +871,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -859,6 +871,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
ret.setAttribute("results", "0"); ret.setAttribute("results", "0");
} }
ret.setAttribute("cached", Boolean.toString(this.cached)); ret.setAttribute("cached", Boolean.toString(this.cached));
ret.setAttribute("etag", cacheETag);
final Element parseTreeElem = new Element("ParseTree"); final Element parseTreeElem = new Element("ParseTree");
if (this.el.hasErrors()) { if (this.el.hasErrors()) {
...@@ -972,4 +985,16 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -972,4 +985,16 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
public Role getRole() { public Role getRole() {
return this.role; return this.role;
} }
/**
* Return the ETag.
*
* <p>The ETag tags the query cache and is renewed each time the cache is being cleared, i.e. each
* time the database is being updated.
*
* @return The ETag
*/
public static String getETag() {
return cacheETag;
}
} }
package org.caosdb.server.query; package org.caosdb.server.query;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import org.caosdb.server.CaosDBServer; import org.caosdb.server.CaosDBServer;
import org.caosdb.server.database.access.InitAccess;
import org.caosdb.server.transaction.WriteTransaction;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
...@@ -61,4 +66,40 @@ public class QueryTest { ...@@ -61,4 +66,40 @@ public class QueryTest {
assertNull(q.getEntity()); assertNull(q.getEntity());
assertEquals(Query.Role.ENTITY, q.getRole()); assertEquals(Query.Role.ENTITY, q.getRole());
} }
/**
* Assure that {@link WriteTransaction#commit()} calls {@link Query#clearCache()}.
*
* Since currently the cache shall be cleared whenever there is a commit.
* */
@Test
public void testEtagChangesAfterWrite() {
String old = Query.getETag();
assertNotNull(old);
WriteTransaction w =
new WriteTransaction(null) {
@Override
public boolean useCache() {
// this function is being overriden purely for the purpose of calling
// commit() (which is protected)
try {
// otherwise the test fails because getAccess() return null;
setAccess(new InitAccess(null));
commit();
} catch (Exception e) {
fail("this should not happen");
}
return false;
}
};
// trigger commit();
w.useCache();
String neu = Query.getETag();
assertNotEquals(old, neu, "old and new tag should not be equal");
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment