aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java346
1 files changed, 346 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java
new file mode 100644
index 00000000..9121fc44
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeProvisioner.java
@@ -0,0 +1,346 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.rete.network;
11
12import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
16import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
17import tools.refinery.viatra.runtime.rete.boundary.InputConnector;
18import tools.refinery.viatra.runtime.rete.construction.plancompiler.CompilerHelper;
19import tools.refinery.viatra.runtime.rete.index.Indexer;
20import tools.refinery.viatra.runtime.rete.index.OnetimeIndexer;
21import tools.refinery.viatra.runtime.rete.index.ProjectionIndexer;
22import tools.refinery.viatra.runtime.rete.network.delayed.DelayedConnectCommand;
23import tools.refinery.viatra.runtime.rete.recipes.*;
24import tools.refinery.viatra.runtime.rete.recipes.helper.RecipeRecognizer;
25import tools.refinery.viatra.runtime.rete.recipes.helper.RecipesHelper;
26import tools.refinery.viatra.runtime.rete.remote.Address;
27import tools.refinery.viatra.runtime.rete.remote.RemoteReceiver;
28import tools.refinery.viatra.runtime.rete.remote.RemoteSupplier;
29import tools.refinery.viatra.runtime.rete.traceability.ActiveNodeConflictTrace;
30import tools.refinery.viatra.runtime.rete.traceability.RecipeTraceInfo;
31import tools.refinery.viatra.runtime.rete.traceability.UserRequestTrace;
32import tools.refinery.viatra.runtime.rete.util.Options;
33
34import java.util.Map;
35import java.util.Set;
36
37/**
38 * Stores the internal parts of a rete network. Nodes are stored according to type and parameters.
39 *
40 * @author Gabor Bergmann
41 */
42public class NodeProvisioner {
43
44 // boolean activeStorage = true;
45
46 ReteContainer reteContainer;
47 NodeFactory nodeFactory;
48 ConnectionFactory connectionFactory;
49 InputConnector inputConnector;
50 IQueryRuntimeContext runtimeContext;
51
52 // TODO as recipe?
53 Map<Supplier, RemoteReceiver> remoteReceivers = CollectionsFactory.createMap();
54 Map<Address<? extends Supplier>, RemoteSupplier> remoteSuppliers = CollectionsFactory.createMap();
55
56 private RecipeRecognizer recognizer;
57
58 /**
59 * PRE: NodeFactory, ConnectionFactory must exist
60 *
61 * @param reteContainer
62 * the ReteNet whose interior is to be mapped.
63 */
64 public NodeProvisioner(ReteContainer reteContainer) {
65 super();
66 this.reteContainer = reteContainer;
67 this.nodeFactory = reteContainer.getNodeFactory();
68 this.connectionFactory = reteContainer.getConnectionFactory();
69 this.inputConnector = reteContainer.getInputConnectionFactory();
70 runtimeContext = reteContainer.getNetwork().getEngine().getRuntimeContext();
71 recognizer = new RecipeRecognizer(runtimeContext);
72 }
73
74 public synchronized Address<? extends Node> getOrCreateNodeByRecipe(RecipeTraceInfo recipeTrace) {
75 ReteNodeRecipe recipe = recipeTrace.getRecipe();
76 Address<? extends Node> result = getNodesByRecipe().get(recipe);
77 if (result != null) {
78 // NODE ALREADY CONSTRUCTED FOR RECIPE, only needs to add trace
79 if (getRecipeTraces().add(recipeTrace))
80 result.getNodeCache().assignTraceInfo(recipeTrace);
81 } else {
82 // No node for this recipe object - but equivalent recipes still
83 // reusable
84 ReteNodeRecipe canonicalRecipe = recognizer.canonicalizeRecipe(recipe);
85 if (canonicalRecipe != recipe) {
86 // FOUND EQUIVALENT RECIPE
87 result = getNodesByRecipe().get(canonicalRecipe);
88 if (result != null) {
89 // NODE ALREADY CONSTRUCTED FOR EQUIVALENT RECIPE
90 recipeTrace.shadowWithEquivalentRecipe(canonicalRecipe);
91 getNodesByRecipe().put(recipe, result);
92 if (getRecipeTraces().add(recipeTrace))
93 result.getNodeCache().assignTraceInfo(recipeTrace);
94 // Bug 491922: ensure that recipe shadowing propagates to
95 // parent traces
96 // note that if equivalentRecipes() becomes more
97 // sophisticated
98 // and considers recipes with different parents, this might
99 // have to be changed
100 ensureParents(recipeTrace);
101 } else {
102 // CONSTRUCTION IN PROGRESS FOR EQUIVALENT RECIPE
103 if (recipe instanceof IndexerRecipe) {
104 // this is allowed for indexers;
105 // go on with the construction, as the same indexer node
106 // will be obtained anyways
107 } else {
108 throw new IllegalStateException(
109 "This should not happen: " + "non-indexer nodes are are supposed to be constructed "
110 + "as soon as they are designated as canonical recipes");
111 }
112 }
113 }
114 if (result == null) {
115 // MUST INSTANTIATE NEW NODE FOR RECIPE
116 final Node freshNode = instantiateNodeForRecipe(recipeTrace, recipe);
117 result = reteContainer.makeAddress(freshNode);
118 }
119 }
120 return result;
121 }
122
123 private Set<RecipeTraceInfo> getRecipeTraces() {
124 return reteContainer.network.recipeTraces;
125 }
126
127 private Node instantiateNodeForRecipe(RecipeTraceInfo recipeTrace, final ReteNodeRecipe recipe) {
128 this.getRecipeTraces().add(recipeTrace);
129 if (recipe instanceof IndexerRecipe) {
130
131 // INSTANTIATE AND HOOK UP
132 // (cannot delay hooking up, because parent determines indexer
133 // implementation)
134 ensureParents(recipeTrace);
135 final ReteNodeRecipe parentRecipe = recipeTrace.getParentRecipeTraces().iterator().next().getRecipe();
136 final Indexer result = nodeFactory.createIndexer(reteContainer, (IndexerRecipe) recipe,
137 asSupplier(
138 (Address<? extends Supplier>) reteContainer.network.getExistingNodeByRecipe(parentRecipe)),
139 recipeTrace);
140
141 // REMEMBER
142 if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER) {
143 getNodesByRecipe().put(recipe, reteContainer.makeAddress(result));
144 }
145
146 return result;
147 } else {
148
149 // INSTANTIATE
150 Node result = nodeFactory.createNode(reteContainer, recipe, recipeTrace);
151
152 // REMEMBER
153 if (Options.nodeSharingOption == Options.NodeSharingOption.ALL) {
154 getNodesByRecipe().put(recipe, reteContainer.makeAddress(result));
155 }
156
157 // HOOK UP
158 // (recursion-tolerant due to this delayed order of initialization)
159 if (recipe instanceof InputRecipe) {
160 inputConnector.connectInput((InputRecipe) recipe, result);
161 } else {
162 if (recipe instanceof InputFilterRecipe)
163 inputConnector.connectInputFilter((InputFilterRecipe) recipe, result);
164 ensureParents(recipeTrace);
165 connectionFactory.connectToParents(recipeTrace, result);
166 }
167 return result;
168 }
169 }
170
171 private Map<ReteNodeRecipe, Address<? extends Node>> getNodesByRecipe() {
172 return reteContainer.network.nodesByRecipe;
173 }
174
175 private void ensureParents(RecipeTraceInfo recipeTrace) {
176 for (RecipeTraceInfo parentTrace : recipeTrace.getParentRecipeTraces()) {
177 getOrCreateNodeByRecipe(parentTrace);
178 }
179 }
180
181 //// Remoting - TODO eliminate?
182
183 synchronized RemoteReceiver accessRemoteReceiver(Address<? extends Supplier> address) {
184 throw new UnsupportedOperationException("Multi-container Rete not supported yet");
185 // if (!reteContainer.isLocal(address))
186 // return
187 // address.getContainer().getProvisioner().accessRemoteReceiver(address);
188 // Supplier localSupplier = reteContainer.resolveLocal(address);
189 // RemoteReceiver result = remoteReceivers.get(localSupplier);
190 // if (result == null) {
191 // result = new RemoteReceiver(reteContainer);
192 // reteContainer.connect(localSupplier, result); // stateless node, no
193 // // synch required
194 //
195 // if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER)
196 // remoteReceivers.put(localSupplier, result);
197 // }
198 // return result;
199 }
200
201 /**
202 * @pre: address is NOT local
203 */
204 synchronized RemoteSupplier accessRemoteSupplier(Address<? extends Supplier> address) {
205 throw new UnsupportedOperationException("Multi-container Rete not supported yet");
206 // RemoteSupplier result = remoteSuppliers.get(address);
207 // if (result == null) {
208 // result = new RemoteSupplier(reteContainer,
209 // address.getContainer().getProvisioner()
210 // .accessRemoteReceiver(address));
211 // // network.connectAndSynchronize(supplier, result);
212 //
213 // if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER)
214 // remoteSuppliers.put(address, result);
215 // }
216 // return result;
217 }
218
219 /**
220 * The powerful method for accessing any (supplier) Address as a local supplier.
221 */
222 public Supplier asSupplier(Address<? extends Supplier> address) {
223 if (!reteContainer.isLocal(address))
224 return accessRemoteSupplier(address);
225 else
226 return reteContainer.resolveLocal(address);
227 }
228
229 /** the composite key tuple is formed as (RecipeTraceInfo, TupleMask) */
230 private Map<Tuple, UserRequestTrace> projectionIndexerUserRequests = CollectionsFactory.createMap();
231
232 // local version
233 // TODO remove?
234 public synchronized ProjectionIndexer accessProjectionIndexer(RecipeTraceInfo productionTrace, TupleMask mask) {
235 Tuple tableKey = Tuples.staticArityFlatTupleOf(productionTrace, mask);
236 UserRequestTrace indexerTrace = projectionIndexerUserRequests.computeIfAbsent(tableKey, k -> {
237 final ProjectionIndexerRecipe projectionIndexerRecipe = projectionIndexerRecipe(
238 productionTrace, mask);
239 return new UserRequestTrace(projectionIndexerRecipe, productionTrace);
240 });
241 final Address<? extends Node> address = getOrCreateNodeByRecipe(indexerTrace);
242 return (ProjectionIndexer) reteContainer.resolveLocal(address);
243 }
244
245 // local version
246 public synchronized ProjectionIndexer accessProjectionIndexerOnetime(RecipeTraceInfo supplierTrace,
247 TupleMask mask) {
248 if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER)
249 return accessProjectionIndexer(supplierTrace, mask);
250
251 final Address<? extends Node> supplierAddress = getOrCreateNodeByRecipe(supplierTrace);
252 Supplier supplier = (Supplier) reteContainer.resolveLocal(supplierAddress);
253
254 OnetimeIndexer result = new OnetimeIndexer(reteContainer, mask);
255 reteContainer.getDelayedCommandQueue().add(new DelayedConnectCommand(supplier, result, reteContainer));
256
257 return result;
258 }
259
260 // local, read-only version
261 public synchronized ProjectionIndexer peekProjectionIndexer(RecipeTraceInfo supplierTrace, TupleMask mask) {
262 final Address<? extends Node> address = getNodesByRecipe().get(projectionIndexerRecipe(supplierTrace, mask));
263 return address == null ? null : (ProjectionIndexer) reteContainer.resolveLocal(address);
264 }
265
266 private ProjectionIndexerRecipe projectionIndexerRecipe(
267 RecipeTraceInfo parentTrace, TupleMask mask) {
268 final ReteNodeRecipe parentRecipe = parentTrace.getRecipe();
269 Tuple tableKey = Tuples.staticArityFlatTupleOf(parentRecipe, mask);
270 ProjectionIndexerRecipe projectionIndexerRecipe = resultSeedRecipes.computeIfAbsent(tableKey, k ->
271 RecipesHelper.projectionIndexerRecipe(parentRecipe, CompilerHelper.toRecipeMask(mask))
272 );
273 return projectionIndexerRecipe;
274 }
275
276 /** the composite key tuple is formed as (ReteNodeRecipe, TupleMask) */
277 private Map<Tuple, ProjectionIndexerRecipe> resultSeedRecipes = CollectionsFactory.createMap();
278
279 // public synchronized Address<? extends Supplier>
280 // accessValueBinderFilterNode(
281 // Address<? extends Supplier> supplierAddress, int bindingIndex, Object
282 // bindingValue) {
283 // Supplier supplier = asSupplier(supplierAddress);
284 // Object[] paramsArray = { supplier.getNodeId(), bindingIndex, bindingValue
285 // };
286 // Tuple params = new FlatTuple(paramsArray);
287 // ValueBinderFilterNode result = valueBinderFilters.get(params);
288 // if (result == null) {
289 // result = new ValueBinderFilterNode(reteContainer, bindingIndex,
290 // bindingValue);
291 // reteContainer.connect(supplier, result); // stateless node, no synch
292 // // required
293 //
294 // if (Options.nodeSharingOption == Options.NodeSharingOption.ALL)
295 // valueBinderFilters.put(params, result);
296 // }
297 // return reteContainer.makeAddress(result);
298 // }
299
300 /**
301 * Returns a copy of the given indexer that is an active node by itself (created if does not exist). (Convention:
302 * attached with same mask to a transparent node that is attached to parent node.) Node is created if it does not
303 * exist yet.
304 *
305 * @return an identical but active indexer
306 */
307 // TODO rethink traceability
308 RecipeTraceInfo accessActiveIndexer(RecipeTraceInfo inactiveIndexerRecipeTrace) {
309 final RecipeTraceInfo parentRecipeTrace = inactiveIndexerRecipeTrace.getParentRecipeTraces().iterator().next();
310 final ProjectionIndexerRecipe inactiveIndexerRecipe = (ProjectionIndexerRecipe) inactiveIndexerRecipeTrace
311 .getRecipe();
312
313 final TransparentRecipe transparentRecipe = RecipesFactory.eINSTANCE.createTransparentRecipe();
314 transparentRecipe.setParent(parentRecipeTrace.getRecipe());
315 final ActiveNodeConflictTrace transparentRecipeTrace = new ActiveNodeConflictTrace(transparentRecipe,
316 parentRecipeTrace, inactiveIndexerRecipeTrace);
317
318 final ProjectionIndexerRecipe activeIndexerRecipe = RecipesFactory.eINSTANCE
319 .createProjectionIndexerRecipe();
320 activeIndexerRecipe.setParent(transparentRecipe);
321 activeIndexerRecipe.setMask(inactiveIndexerRecipe.getMask());
322 final ActiveNodeConflictTrace activeIndexerRecipeTrace = new ActiveNodeConflictTrace(activeIndexerRecipe,
323 transparentRecipeTrace, inactiveIndexerRecipeTrace);
324
325 return activeIndexerRecipeTrace;
326 }
327
328 // /**
329 // * @param parent
330 // * @return
331 // */
332 // private TransparentNode accessTransparentNodeInternal(Supplier parent) {
333 // nodeFactory.
334 // return null;
335 // }
336
337 // public synchronized void registerSpecializedProjectionIndexer(Node node,
338 // ProjectionIndexer indexer) {
339 // if (Options.nodeSharingOption != Options.NodeSharingOption.NEVER) {
340 // Object[] paramsArray = { node.getNodeId(), indexer.getMask() };
341 // Tuple params = new FlatTuple(paramsArray);
342 // projectionIndexers.put(params, indexer);
343 // }
344 // }
345
346}