Skip to content
Snippets Groups Projects
Commit 7219bc7f authored by Jesper's avatar Jesper
Browse files

Implement flushing for concurrent evaluation

ASTNode.flushTreeCache() was not implemented when generating code for
concurrent evaluation.  This makes flushing work with concurrent evaluation.
However, note that flushing is only safe if no other thread is concurrently
evaluating attributes or trying to flush the cache.

fixes #289 (bitbucket)
parent e14131a4
No related branches found
No related tags found
No related merge requests found
2018-03-21 Jesper Öqvist <jesper.oqvist@cs.lth.se>
* Added flushing for concurrent evaluation.
2018-02-19 Jesper Öqvist <jesper.oqvist@cs.lth.se> 2018-02-19 Jesper Öqvist <jesper.oqvist@cs.lth.se>
* Added support for Java 8 syntax in aspects (lambdas, method references, * Added support for Java 8 syntax in aspects (lambdas, method references,
......
...@@ -37,30 +37,52 @@ aspect Flush { ...@@ -37,30 +37,52 @@ aspect Flush {
// TODO: Figure out if flushing of NTAs are missing when this is excluded // TODO: Figure out if flushing of NTAs are missing when this is excluded
//tt.bind("FlushNTACache", emitFlushNTACacheString()); //tt.bind("FlushNTACache", emitFlushNTACacheString());
StringBuilder sb = new StringBuilder(); if (config().concurrentEval()) {
for (AttrDecl attr : listOfCachedAttributes()) {
sb.append(attr.signature() + "_reset();\n");
}
tt.bind("FlushAttrCacheBody", sb.toString());
StringBuilder fresh = new StringBuilder(); StringBuilder fresh = new StringBuilder();
for (Iterator itr = listOfCachedAttributes().iterator(); itr.hasNext();) { for (AttrDecl attr : listOfCachedAttributes()) {
AttrDecl attr = (AttrDecl) itr.next();
fresh.append(attr.signature() + "_fresh();\n"); fresh.append(attr.signature() + "_fresh();\n");
} }
for (CollDecl decl : interfaceCollDecls()) {
fresh.append(
decl.signature() + "_value = new AtomicReference<Object>(AttributeValue.NONE);\n");
if (decl.root() == this) {
fresh.append(decl.templateContext().expand("Collection.makeFresh"));
}
}
for (CollDecl decl : getCollDeclList()) {
fresh.append(
decl.signature() + "_value = new AtomicReference<Object>(AttributeValue.NONE);\n");
if (decl.root() == this) {
fresh.append(decl.templateContext().expand("Collection.makeFresh"));
}
}
tt.bind("MakeFreshNodeBody", fresh.toString()); tt.bind("MakeFreshNodeBody", fresh.toString());
tt.expand("ASTDecl.makeFreshNode", out);
}
StringBuilder sb = new StringBuilder();
for (AttrDecl attr : listOfCachedAttributes()) {
sb.append(attr.signature() + "_reset();\n");
}
tt.bind("FlushAttrCacheBody", sb.toString());
tt.expand("ASTDecl.flushAttrCacheMethod", out); tt.expand("ASTDecl.flushAttrCacheMethod", out);
tt.expand("ASTDecl.flushCollectionCacheMethod", out); tt.expand("ASTDecl.flushCollectionCacheMethod", out);
} }
syn String AttrDecl.resetCache() = templateContext().expand("AttrDecl.resetAttrCache"); syn String AttrDecl.resetCache() = config().concurrentEval()
? templateContext().expand("AttrDecl.resetAttrCache:concurrent")
: templateContext().expand("AttrDecl.resetAttrCache");
syn String AttrDecl.resetVisit() = templateContext().expand("AttrDecl.resetAttrVisit"); syn String AttrDecl.resetVisit() = config().concurrentEval()
? templateContext().expand("AttrDecl.resetAttrVisit:concurrent")
: templateContext().expand("AttrDecl.resetAttrVisit");
public void AttrDecl.emitResetMethod(PrintStream out) { public void AttrDecl.emitResetMethod(PrintStream out) {
if (isMemoized()) { if (isMemoized()) {
templateContext().expand("AttrDecl.resetMethod", out); templateContext().expand("AttrDecl.resetMethod", out);
if (config().concurrentEval()) {
templateContext().expand("AttrDecl.makeFresh", out);
}
} }
} }
......
...@@ -25,17 +25,10 @@ ...@@ -25,17 +25,10 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
AttrDecl.resetAttrCache [[]] # Used to refresh a cloned node to a fresh state.
# Note: atomic references need to be replaced since this is a fresh object,
AttrDecl.resetAttrVisit [[]] # otherwise there would be cache sharing between separate nodes.
ASTDecl.makeFreshNode [[
ASTDecl.flushAttrCacheMethod [[
$if(FlushAttr)
/** @apilevel internal */
public void #name.flushAttrCache() {
// Flushing is not needed. Caches cleared when cloning.
}
$endif
/** @apilevel internal */ /** @apilevel internal */
public void #name.makeFreshNode() { public void #name.makeFreshNode() {
$if(!#isASTNodeDecl) $if(!#isASTNodeDecl)
...@@ -45,13 +38,66 @@ $endif ...@@ -45,13 +38,66 @@ $endif
} }
]] ]]
# Reset all attribute caches. # Resets all caches for a collection attribute.
Collection.makeFresh [[
$if(#onePhase)
collect_contributors_#collectionId = false;
$else
contributorMap_#collectionId = null;
$if(Concurrent)
surveyLock_#collectionId = new Object();
$endif
$endif
]]
AttrDecl.resetMethod [[ AttrDecl.resetMethod [[
$if(FlushAttr)
/** @apilevel internal */ /** @apilevel internal */
private void #(signature)_reset() { private void #(signature)_reset() {
// Handled by creating a fresh copy of this node! $include(AttrDecl.traceFlushAttr)
$if(Concurrent)
$include(AttrDecl.resetAttrCache:concurrent)
$include(AttrDecl.resetAttrVisit:concurrent)
$else
$include(AttrDecl.resetAttrCache)
$include(AttrDecl.resetAttrVisit)
$endif
} }
$endif
]]
# There are some things that don't need to be reset when flushing
# a node to a non-fresh state:
# - NTA proxy objects
# - atomic references
# - id objects
# Note: circular attribute values can be reset instead of creating a new
# object but this not implemented yet.
AttrDecl.resetAttrCache:concurrent [[
$if(#isParameterized)
#(signature)_values.clear();
$else
$if(#isCircular)
#(signature)_value = new CircularAttributeValue();
$else
$if(#isIdentityComparable)
#(signature)_computed = false;
$if(#cacheInCycle)
#(signature)_id = new Object();
$endif
$else
#(signature)_value.set(AttributeValue.NONE);
$endif
$endif
$endif
]]
# TODO(joqvist): implement this!
AttrDecl.resetAttrVisit:concurrent [[
]]
# Reset all attribute caches.
AttrDecl.makeFresh [[
/** @apilevel internal */ /** @apilevel internal */
private void #(signature)_fresh() { private void #(signature)_fresh() {
$if(#isParameterized) $if(#isParameterized)
...@@ -79,3 +125,13 @@ $else ...@@ -79,3 +125,13 @@ $else
$endif $endif
} }
]] ]]
# The clone is not flushed in concurrent mode:
# makeFreshNode() will take care of flushing it in treeCopy().
ASTDecl.emitCloneNode [[
/** @apilevel internal */
#annotations
public #copyReturnType #name.clone() throws CloneNotSupportedException {
return (#name) super.clone();
}
]]
...@@ -68,14 +68,12 @@ $if(FlushEnabled) ...@@ -68,14 +68,12 @@ $if(FlushEnabled)
$if(#isASTNodeDecl) $if(#isASTNodeDecl)
/** @apilevel internal */ /** @apilevel internal */
public void #name.flushAttrAndCollectionCache() { public void #name.flushAttrAndCollectionCache() {
$SynchBegin
$if(FlushAttr) $if(FlushAttr)
flushAttrCache(); flushAttrCache();
$endif $endif
$if(FlushColl) $if(FlushColl)
flushCollectionCache(); flushCollectionCache();
$endif $endif
$SynchEnd
} }
$endif $endif
$endif $endif
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment