Committed by
Gerrit Code Review
Refactor transaction support in preparation for migration to latest APIs
- Added a explicit transaction id type - cli command now just returns the identifiers of in-progress transactions - Removed redriveTransactions until a better alternative is provided - Removed DatabaseUpdate and replaced its usage with MapUpdate Change-Id: Ic4a14967072068834510cd8459fd2a6790e456ef
Showing
34 changed files
with
389 additions
and
702 deletions
... | @@ -18,81 +18,41 @@ package org.onosproject.cli.net; | ... | @@ -18,81 +18,41 @@ package org.onosproject.cli.net; |
18 | import java.util.Collection; | 18 | import java.util.Collection; |
19 | 19 | ||
20 | import org.apache.karaf.shell.commands.Command; | 20 | import org.apache.karaf.shell.commands.Command; |
21 | -import org.apache.karaf.shell.commands.Option; | ||
22 | -import org.onlab.util.Tools; | ||
23 | import org.onosproject.cli.AbstractShellCommand; | 21 | import org.onosproject.cli.AbstractShellCommand; |
22 | +import org.onosproject.store.primitives.TransactionId; | ||
24 | import org.onosproject.store.service.StorageAdminService; | 23 | import org.onosproject.store.service.StorageAdminService; |
25 | -import org.onosproject.store.service.Transaction; | ||
26 | 24 | ||
27 | import com.fasterxml.jackson.databind.JsonNode; | 25 | import com.fasterxml.jackson.databind.JsonNode; |
28 | import com.fasterxml.jackson.databind.ObjectMapper; | 26 | import com.fasterxml.jackson.databind.ObjectMapper; |
29 | import com.fasterxml.jackson.databind.node.ArrayNode; | 27 | import com.fasterxml.jackson.databind.node.ArrayNode; |
30 | -import com.fasterxml.jackson.databind.node.ObjectNode; | ||
31 | 28 | ||
32 | /** | 29 | /** |
33 | - * CLI to work with database transactions in the system. | 30 | + * CLI to view in-progress database transactions in the system. |
34 | */ | 31 | */ |
35 | @Command(scope = "onos", name = "transactions", | 32 | @Command(scope = "onos", name = "transactions", |
36 | - description = "Utility for viewing and redriving database transactions") | 33 | + description = "Utility for listing pending/inprogress transactions") |
37 | public class TransactionsCommand extends AbstractShellCommand { | 34 | public class TransactionsCommand extends AbstractShellCommand { |
38 | 35 | ||
39 | - @Option(name = "-r", aliases = "--redrive", | ||
40 | - description = "Redrive stuck transactions while removing those that are done", | ||
41 | - required = false, multiValued = false) | ||
42 | - private boolean redrive = false; | ||
43 | - | ||
44 | - private static final String FMT = "%-20s %-15s %-10s"; | ||
45 | - | ||
46 | - /** | ||
47 | - * Displays transactions as text. | ||
48 | - * | ||
49 | - * @param transactions transactions | ||
50 | - */ | ||
51 | - private void displayTransactions(Collection<Transaction> transactions) { | ||
52 | - print("---------------------------------------------"); | ||
53 | - print(FMT, "Id", "State", "Updated"); | ||
54 | - print("---------------------------------------------"); | ||
55 | - transactions.forEach(txn -> print(FMT, txn.id(), txn.state(), Tools.timeAgo(txn.lastUpdated()))); | ||
56 | - if (transactions.size() > 0) { | ||
57 | - print("---------------------------------------------"); | ||
58 | - } | ||
59 | - } | ||
60 | - | ||
61 | /** | 36 | /** |
62 | * Converts collection of transactions into a JSON object. | 37 | * Converts collection of transactions into a JSON object. |
63 | * | 38 | * |
64 | - * @param transactions transactions | 39 | + * @param transactionIds transaction identifiers |
65 | */ | 40 | */ |
66 | - private JsonNode json(Collection<Transaction> transactions) { | 41 | + private JsonNode json(Collection<TransactionId> transactionIds) { |
67 | ObjectMapper mapper = new ObjectMapper(); | 42 | ObjectMapper mapper = new ObjectMapper(); |
68 | ArrayNode txns = mapper.createArrayNode(); | 43 | ArrayNode txns = mapper.createArrayNode(); |
69 | - | 44 | + transactionIds.forEach(id -> txns.add(id.toString())); |
70 | - // Create a JSON node for each transaction | ||
71 | - transactions.stream().forEach(txn -> { | ||
72 | - ObjectNode txnNode = mapper.createObjectNode(); | ||
73 | - txnNode.put("id", txn.id()) | ||
74 | - .put("state", txn.state().toString()) | ||
75 | - .put("lastUpdated", txn.lastUpdated()); | ||
76 | - txns.add(txnNode); | ||
77 | - }); | ||
78 | - | ||
79 | return txns; | 45 | return txns; |
80 | } | 46 | } |
81 | 47 | ||
82 | @Override | 48 | @Override |
83 | protected void execute() { | 49 | protected void execute() { |
84 | StorageAdminService storageAdminService = get(StorageAdminService.class); | 50 | StorageAdminService storageAdminService = get(StorageAdminService.class); |
85 | - | 51 | + Collection<TransactionId> transactionIds = storageAdminService.getPendingTransactions(); |
86 | - if (redrive) { | ||
87 | - storageAdminService.redriveTransactions(); | ||
88 | - return; | ||
89 | - } | ||
90 | - | ||
91 | - Collection<Transaction> transactions = storageAdminService.getTransactions(); | ||
92 | if (outputJson()) { | 52 | if (outputJson()) { |
93 | - print("%s", json(transactions)); | 53 | + print("%s", json(transactionIds)); |
94 | } else { | 54 | } else { |
95 | - displayTransactions(transactions); | 55 | + transactionIds.forEach(id -> print("%s", id.toString())); |
96 | } | 56 | } |
97 | } | 57 | } |
98 | } | 58 | } | ... | ... |
... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onosproject.store.primitives.resources.impl; | 16 | +package org.onosproject.store.primitives; |
17 | 17 | ||
18 | import com.google.common.base.Objects; | 18 | import com.google.common.base.Objects; |
19 | 19 | ... | ... |
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -package org.onosproject.store.service; | ||
18 | - | ||
19 | -import static com.google.common.base.Preconditions.checkArgument; | ||
20 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
21 | -import static com.google.common.base.Preconditions.checkState; | ||
22 | - | ||
23 | -import com.google.common.base.MoreObjects; | ||
24 | - | ||
25 | -/** | ||
26 | - * Database update operation. | ||
27 | - * | ||
28 | - */ | ||
29 | -public final class DatabaseUpdate { | ||
30 | - | ||
31 | - /** | ||
32 | - * Type of database update operation. | ||
33 | - */ | ||
34 | - public enum Type { | ||
35 | - /** | ||
36 | - * Insert/Update entry without any checks. | ||
37 | - */ | ||
38 | - PUT, | ||
39 | - /** | ||
40 | - * Insert an entry iff there is no existing entry for that key. | ||
41 | - */ | ||
42 | - PUT_IF_ABSENT, | ||
43 | - | ||
44 | - /** | ||
45 | - * Update entry if the current version matches specified version. | ||
46 | - */ | ||
47 | - PUT_IF_VERSION_MATCH, | ||
48 | - | ||
49 | - /** | ||
50 | - * Update entry if the current value matches specified value. | ||
51 | - */ | ||
52 | - PUT_IF_VALUE_MATCH, | ||
53 | - | ||
54 | - /** | ||
55 | - * Remove entry without any checks. | ||
56 | - */ | ||
57 | - REMOVE, | ||
58 | - | ||
59 | - /** | ||
60 | - * Remove entry if the current version matches specified version. | ||
61 | - */ | ||
62 | - REMOVE_IF_VERSION_MATCH, | ||
63 | - | ||
64 | - /** | ||
65 | - * Remove entry if the current value matches specified value. | ||
66 | - */ | ||
67 | - REMOVE_IF_VALUE_MATCH, | ||
68 | - } | ||
69 | - | ||
70 | - private Type type; | ||
71 | - private String mapName; | ||
72 | - private String key; | ||
73 | - private byte[] value; | ||
74 | - private byte[] currentValue; | ||
75 | - private long currentVersion = -1; | ||
76 | - | ||
77 | - /** | ||
78 | - * Returns the type of update operation. | ||
79 | - * @return type of update. | ||
80 | - */ | ||
81 | - public Type type() { | ||
82 | - return type; | ||
83 | - } | ||
84 | - | ||
85 | - /** | ||
86 | - * Returns the name of map being updated. | ||
87 | - * @return map name. | ||
88 | - */ | ||
89 | - public String mapName() { | ||
90 | - return mapName; | ||
91 | - } | ||
92 | - | ||
93 | - /** | ||
94 | - * Returns the item key being updated. | ||
95 | - * @return item key | ||
96 | - */ | ||
97 | - public String key() { | ||
98 | - return key; | ||
99 | - } | ||
100 | - | ||
101 | - /** | ||
102 | - * Returns the new value. | ||
103 | - * @return item's target value. | ||
104 | - */ | ||
105 | - public byte[] value() { | ||
106 | - return value; | ||
107 | - } | ||
108 | - | ||
109 | - /** | ||
110 | - * Returns the expected current value in the database value for the key. | ||
111 | - * @return current value in database. | ||
112 | - */ | ||
113 | - public byte[] currentValue() { | ||
114 | - return currentValue; | ||
115 | - } | ||
116 | - | ||
117 | - /** | ||
118 | - * Returns the expected current version in the database for the key. | ||
119 | - * @return expected version. | ||
120 | - */ | ||
121 | - public long currentVersion() { | ||
122 | - return currentVersion; | ||
123 | - } | ||
124 | - | ||
125 | - @Override | ||
126 | - public String toString() { | ||
127 | - return MoreObjects.toStringHelper(this) | ||
128 | - .add("type", type) | ||
129 | - .add("mapName", mapName) | ||
130 | - .add("key", key) | ||
131 | - .add("value", value) | ||
132 | - .add("currentValue", currentValue) | ||
133 | - .add("currentVersion", currentVersion) | ||
134 | - .toString(); | ||
135 | - } | ||
136 | - | ||
137 | - /** | ||
138 | - * Creates a new builder instance. | ||
139 | - * | ||
140 | - * @return builder. | ||
141 | - */ | ||
142 | - public static Builder newBuilder() { | ||
143 | - return new Builder(); | ||
144 | - } | ||
145 | - | ||
146 | - /** | ||
147 | - * DatabaseUpdate builder. | ||
148 | - * | ||
149 | - */ | ||
150 | - public static final class Builder { | ||
151 | - | ||
152 | - private DatabaseUpdate update = new DatabaseUpdate(); | ||
153 | - | ||
154 | - public DatabaseUpdate build() { | ||
155 | - validateInputs(); | ||
156 | - return update; | ||
157 | - } | ||
158 | - | ||
159 | - public Builder withType(Type type) { | ||
160 | - update.type = checkNotNull(type, "type cannot be null"); | ||
161 | - return this; | ||
162 | - } | ||
163 | - | ||
164 | - public Builder withMapName(String mapName) { | ||
165 | - update.mapName = checkNotNull(mapName, "mapName cannot be null"); | ||
166 | - return this; | ||
167 | - } | ||
168 | - | ||
169 | - public Builder withKey(String key) { | ||
170 | - update.key = checkNotNull(key, "key cannot be null"); | ||
171 | - return this; | ||
172 | - } | ||
173 | - | ||
174 | - public Builder withCurrentValue(byte[] value) { | ||
175 | - update.currentValue = checkNotNull(value, "currentValue cannot be null"); | ||
176 | - return this; | ||
177 | - } | ||
178 | - | ||
179 | - public Builder withValue(byte[] value) { | ||
180 | - update.value = checkNotNull(value, "value cannot be null"); | ||
181 | - return this; | ||
182 | - } | ||
183 | - | ||
184 | - public Builder withCurrentVersion(long version) { | ||
185 | - checkArgument(version >= 0, "version cannot be negative"); | ||
186 | - update.currentVersion = version; | ||
187 | - return this; | ||
188 | - } | ||
189 | - | ||
190 | - private void validateInputs() { | ||
191 | - checkNotNull(update.type, "type must be specified"); | ||
192 | - checkNotNull(update.mapName, "map name must be specified"); | ||
193 | - checkNotNull(update.key, "key must be specified"); | ||
194 | - switch (update.type) { | ||
195 | - case PUT: | ||
196 | - case PUT_IF_ABSENT: | ||
197 | - checkNotNull(update.value, "value must be specified."); | ||
198 | - break; | ||
199 | - case PUT_IF_VERSION_MATCH: | ||
200 | - checkNotNull(update.value, "value must be specified."); | ||
201 | - checkState(update.currentVersion >= 0, "current version must be specified"); | ||
202 | - break; | ||
203 | - case PUT_IF_VALUE_MATCH: | ||
204 | - checkNotNull(update.value, "value must be specified."); | ||
205 | - checkNotNull(update.currentValue, "currentValue must be specified."); | ||
206 | - break; | ||
207 | - case REMOVE: | ||
208 | - break; | ||
209 | - case REMOVE_IF_VERSION_MATCH: | ||
210 | - checkState(update.currentVersion >= 0, "current version must be specified"); | ||
211 | - break; | ||
212 | - case REMOVE_IF_VALUE_MATCH: | ||
213 | - checkNotNull(update.currentValue, "currentValue must be specified."); | ||
214 | - break; | ||
215 | - default: | ||
216 | - throw new IllegalStateException("Unknown operation type"); | ||
217 | - } | ||
218 | - } | ||
219 | - } | ||
220 | -} |
... | @@ -61,7 +61,12 @@ public interface DistributedPrimitive { | ... | @@ -61,7 +61,12 @@ public interface DistributedPrimitive { |
61 | /** | 61 | /** |
62 | * Leader elector. | 62 | * Leader elector. |
63 | */ | 63 | */ |
64 | - LEADER_ELECTOR | 64 | + LEADER_ELECTOR, |
65 | + | ||
66 | + /** | ||
67 | + * Transaction Context. | ||
68 | + */ | ||
69 | + TRANSACTION_CONTEXT | ||
65 | } | 70 | } |
66 | 71 | ||
67 | static final long DEFAULT_OPERTATION_TIMEOUT_MILLIS = 5000L; | 72 | static final long DEFAULT_OPERTATION_TIMEOUT_MILLIS = 5000L; | ... | ... |
... | @@ -19,6 +19,8 @@ import java.util.Collection; | ... | @@ -19,6 +19,8 @@ import java.util.Collection; |
19 | import java.util.List; | 19 | import java.util.List; |
20 | import java.util.Map; | 20 | import java.util.Map; |
21 | 21 | ||
22 | +import org.onosproject.store.primitives.TransactionId; | ||
23 | + | ||
22 | /** | 24 | /** |
23 | * Service for administering storage instances. | 25 | * Service for administering storage instances. |
24 | */ | 26 | */ |
... | @@ -62,14 +64,9 @@ public interface StorageAdminService { | ... | @@ -62,14 +64,9 @@ public interface StorageAdminService { |
62 | Map<String, Long> getInMemoryDatabaseCounters(); | 64 | Map<String, Long> getInMemoryDatabaseCounters(); |
63 | 65 | ||
64 | /** | 66 | /** |
65 | - * Returns all the transactions in the system. | 67 | + * Returns all pending transactions. |
66 | * | 68 | * |
67 | - * @return collection of transactions | 69 | + * @return collection of pending transaction identifiers. |
68 | - */ | ||
69 | - Collection<Transaction> getTransactions(); | ||
70 | - | ||
71 | - /** | ||
72 | - * Redrives stuck transactions while removing those that are done. | ||
73 | */ | 70 | */ |
74 | - void redriveTransactions(); | 71 | + Collection<TransactionId> getPendingTransactions(); |
75 | } | 72 | } | ... | ... |
... | @@ -16,6 +16,8 @@ | ... | @@ -16,6 +16,8 @@ |
16 | 16 | ||
17 | package org.onosproject.store.service; | 17 | package org.onosproject.store.service; |
18 | 18 | ||
19 | +import org.onosproject.store.primitives.TransactionId; | ||
20 | + | ||
19 | /** | 21 | /** |
20 | * Provides a context for transactional operations. | 22 | * Provides a context for transactional operations. |
21 | * <p> | 23 | * <p> |
... | @@ -31,14 +33,19 @@ package org.onosproject.store.service; | ... | @@ -31,14 +33,19 @@ package org.onosproject.store.service; |
31 | * context isolation level is REPEATABLE_READS i.e. only data that is committed can be read. | 33 | * context isolation level is REPEATABLE_READS i.e. only data that is committed can be read. |
32 | * The only uncommitted data that can be read is the data modified by the current transaction. | 34 | * The only uncommitted data that can be read is the data modified by the current transaction. |
33 | */ | 35 | */ |
34 | -public interface TransactionContext { | 36 | +public interface TransactionContext extends DistributedPrimitive { |
37 | + | ||
38 | + @Override | ||
39 | + default DistributedPrimitive.Type type() { | ||
40 | + return DistributedPrimitive.Type.TRANSACTION_CONTEXT; | ||
41 | + } | ||
35 | 42 | ||
36 | /** | 43 | /** |
37 | - * Returns the unique transactionId. | 44 | + * Returns the transaction identifier. |
38 | * | 45 | * |
39 | * @return transaction id | 46 | * @return transaction id |
40 | */ | 47 | */ |
41 | - long transactionId(); | 48 | + TransactionId transactionId(); |
42 | 49 | ||
43 | /** | 50 | /** |
44 | * Returns if this transaction context is open. | 51 | * Returns if this transaction context is open. | ... | ... |
... | @@ -15,33 +15,14 @@ | ... | @@ -15,33 +15,14 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.service; | 16 | package org.onosproject.store.service; |
17 | 17 | ||
18 | -/** | 18 | +import org.onosproject.store.primitives.DistributedPrimitiveBuilder; |
19 | - * Interface definition for a transaction context builder. | ||
20 | - */ | ||
21 | -public interface TransactionContextBuilder { | ||
22 | 19 | ||
23 | - /** | 20 | +/** |
24 | - * Disables distribution of map entries across multiple database partitions. | 21 | + * Abstract base class for a transaction context builder. |
25 | - * <p> | ||
26 | - * When partitioning is disabled, the returned map will have a single | ||
27 | - * partition that spans the entire cluster. Furthermore, the changes made to | ||
28 | - * the map are ephemeral and do not survive a full cluster restart. | ||
29 | - * </p> | ||
30 | - * <p> | ||
31 | - * Note: By default, partitions are enabled. This feature is intended to | ||
32 | - * simplify debugging. | ||
33 | - * </p> | ||
34 | - * | ||
35 | - * @return this TransactionalContextBuilder | ||
36 | */ | 22 | */ |
37 | - TransactionContextBuilder withPartitionsDisabled(); | 23 | +public abstract class TransactionContextBuilder extends DistributedPrimitiveBuilder<TransactionContext> { |
38 | 24 | ||
39 | - /** | 25 | + public TransactionContextBuilder() { |
40 | - * Builds a TransactionContext based on configuration options supplied to this | 26 | + super(DistributedPrimitive.Type.TRANSACTION_CONTEXT); |
41 | - * builder. | 27 | + } |
42 | - * | ||
43 | - * @return a new TransactionalContext | ||
44 | - * @throws java.lang.RuntimeException if a mandatory parameter is missing | ||
45 | - */ | ||
46 | - TransactionContext build(); | ||
47 | } | 28 | } | ... | ... |
... | @@ -32,6 +32,7 @@ import java.util.Scanner; | ... | @@ -32,6 +32,7 @@ import java.util.Scanner; |
32 | import org.onlab.util.Match; | 32 | import org.onlab.util.Match; |
33 | import org.onosproject.cluster.NodeId; | 33 | import org.onosproject.cluster.NodeId; |
34 | import org.onosproject.event.Change; | 34 | import org.onosproject.event.Change; |
35 | +import org.onosproject.store.primitives.TransactionId; | ||
35 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands; | 36 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands; |
36 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapState; | 37 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapState; |
37 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorCommands; | 38 | import org.onosproject.store.primitives.resources.impl.AtomixLeaderElectorCommands; |
... | @@ -40,8 +41,6 @@ import org.onosproject.store.primitives.resources.impl.MapEntryUpdateResult; | ... | @@ -40,8 +41,6 @@ import org.onosproject.store.primitives.resources.impl.MapEntryUpdateResult; |
40 | import org.onosproject.store.primitives.resources.impl.MapUpdate; | 41 | import org.onosproject.store.primitives.resources.impl.MapUpdate; |
41 | import org.onosproject.store.primitives.resources.impl.PrepareResult; | 42 | import org.onosproject.store.primitives.resources.impl.PrepareResult; |
42 | import org.onosproject.store.primitives.resources.impl.RollbackResult; | 43 | import org.onosproject.store.primitives.resources.impl.RollbackResult; |
43 | -import org.onosproject.store.primitives.resources.impl.TransactionId; | ||
44 | -import org.onosproject.store.primitives.resources.impl.TransactionalMapUpdate; | ||
45 | import org.onosproject.store.serializers.KryoNamespaces; | 44 | import org.onosproject.store.serializers.KryoNamespaces; |
46 | import org.onosproject.store.service.MapEvent; | 45 | import org.onosproject.store.service.MapEvent; |
47 | import org.onosproject.store.service.Versioned; | 46 | import org.onosproject.store.service.Versioned; |
... | @@ -66,7 +65,8 @@ public final class CatalystSerializers { | ... | @@ -66,7 +65,8 @@ public final class CatalystSerializers { |
66 | MapEntryUpdateResult.Status.class, | 65 | MapEntryUpdateResult.Status.class, |
67 | MapUpdate.class, | 66 | MapUpdate.class, |
68 | MapUpdate.Type.class, | 67 | MapUpdate.Type.class, |
69 | - TransactionalMapUpdate.class, | 68 | + Transaction.class, |
69 | + Transaction.State.class, | ||
70 | TransactionId.class, | 70 | TransactionId.class, |
71 | PrepareResult.class, | 71 | PrepareResult.class, |
72 | CommitResult.class, | 72 | CommitResult.class, |
... | @@ -99,7 +99,8 @@ public final class CatalystSerializers { | ... | @@ -99,7 +99,8 @@ public final class CatalystSerializers { |
99 | serializer.register(Match.class, factory); | 99 | serializer.register(Match.class, factory); |
100 | serializer.register(MapEntryUpdateResult.class, factory); | 100 | serializer.register(MapEntryUpdateResult.class, factory); |
101 | serializer.register(MapEntryUpdateResult.Status.class, factory); | 101 | serializer.register(MapEntryUpdateResult.Status.class, factory); |
102 | - serializer.register(TransactionalMapUpdate.class, factory); | 102 | + serializer.register(Transaction.class, factory); |
103 | + serializer.register(Transaction.State.class, factory); | ||
103 | serializer.register(PrepareResult.class, factory); | 104 | serializer.register(PrepareResult.class, factory); |
104 | serializer.register(CommitResult.class, factory); | 105 | serializer.register(CommitResult.class, factory); |
105 | serializer.register(RollbackResult.class, factory); | 106 | serializer.register(RollbackResult.class, factory); | ... | ... |
... | @@ -24,6 +24,7 @@ import java.util.Collection; | ... | @@ -24,6 +24,7 @@ import java.util.Collection; |
24 | import java.util.List; | 24 | import java.util.List; |
25 | import java.util.Map; | 25 | import java.util.Map; |
26 | import java.util.Set; | 26 | import java.util.Set; |
27 | +import java.util.UUID; | ||
27 | import java.util.concurrent.CompletableFuture; | 28 | import java.util.concurrent.CompletableFuture; |
28 | import java.util.concurrent.ExecutionException; | 29 | import java.util.concurrent.ExecutionException; |
29 | import java.util.concurrent.Executors; | 30 | import java.util.concurrent.Executors; |
... | @@ -46,7 +47,6 @@ import net.kuujo.copycat.protocol.Consistency; | ... | @@ -46,7 +47,6 @@ import net.kuujo.copycat.protocol.Consistency; |
46 | import net.kuujo.copycat.protocol.Protocol; | 47 | import net.kuujo.copycat.protocol.Protocol; |
47 | import net.kuujo.copycat.util.concurrent.NamedThreadFactory; | 48 | import net.kuujo.copycat.util.concurrent.NamedThreadFactory; |
48 | 49 | ||
49 | -import org.apache.commons.lang.math.RandomUtils; | ||
50 | import org.apache.felix.scr.annotations.Activate; | 50 | import org.apache.felix.scr.annotations.Activate; |
51 | import org.apache.felix.scr.annotations.Component; | 51 | import org.apache.felix.scr.annotations.Component; |
52 | import org.apache.felix.scr.annotations.Deactivate; | 52 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -63,10 +63,12 @@ import org.onosproject.cluster.ControllerNode; | ... | @@ -63,10 +63,12 @@ import org.onosproject.cluster.ControllerNode; |
63 | import org.onosproject.cluster.NodeId; | 63 | import org.onosproject.cluster.NodeId; |
64 | import org.onosproject.cluster.PartitionId; | 64 | import org.onosproject.cluster.PartitionId; |
65 | import org.onosproject.core.ApplicationId; | 65 | import org.onosproject.core.ApplicationId; |
66 | -import org.onosproject.core.IdGenerator; | ||
67 | import org.onosproject.persistence.PersistenceService; | 66 | import org.onosproject.persistence.PersistenceService; |
68 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 67 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
68 | +import org.onosproject.store.primitives.TransactionId; | ||
69 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; | ||
69 | import org.onosproject.store.serializers.KryoNamespaces; | 70 | import org.onosproject.store.serializers.KryoNamespaces; |
71 | +import org.onosproject.store.service.AsyncConsistentMap; | ||
70 | import org.onosproject.store.service.AtomicCounterBuilder; | 72 | import org.onosproject.store.service.AtomicCounterBuilder; |
71 | import org.onosproject.store.service.AtomicValueBuilder; | 73 | import org.onosproject.store.service.AtomicValueBuilder; |
72 | import org.onosproject.store.service.ConsistentMapBuilder; | 74 | import org.onosproject.store.service.ConsistentMapBuilder; |
... | @@ -79,7 +81,6 @@ import org.onosproject.store.service.PartitionInfo; | ... | @@ -79,7 +81,6 @@ import org.onosproject.store.service.PartitionInfo; |
79 | import org.onosproject.store.service.Serializer; | 81 | import org.onosproject.store.service.Serializer; |
80 | import org.onosproject.store.service.StorageAdminService; | 82 | import org.onosproject.store.service.StorageAdminService; |
81 | import org.onosproject.store.service.StorageService; | 83 | import org.onosproject.store.service.StorageService; |
82 | -import org.onosproject.store.service.Transaction; | ||
83 | import org.onosproject.store.service.TransactionContextBuilder; | 84 | import org.onosproject.store.service.TransactionContextBuilder; |
84 | import org.slf4j.Logger; | 85 | import org.slf4j.Logger; |
85 | 86 | ||
... | @@ -112,7 +113,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -112,7 +113,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
112 | protected NodeId localNodeId; | 113 | protected NodeId localNodeId; |
113 | 114 | ||
114 | private TransactionManager transactionManager; | 115 | private TransactionManager transactionManager; |
115 | - private final IdGenerator transactionIdGenerator = () -> RandomUtils.nextLong(); | 116 | + private final Supplier<TransactionId> transactionIdGenerator = |
117 | + () -> TransactionId.from(UUID.randomUUID().toString()); | ||
116 | 118 | ||
117 | private ApplicationListener appListener = new InternalApplicationListener(); | 119 | private ApplicationListener appListener = new InternalApplicationListener(); |
118 | 120 | ||
... | @@ -212,7 +214,17 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -212,7 +214,17 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
212 | 214 | ||
213 | Futures.getUnchecked(status); | 215 | Futures.getUnchecked(status); |
214 | 216 | ||
215 | - transactionManager = new TransactionManager(partitionedDatabase, consistentMapBuilder()); | 217 | + AsyncConsistentMap<TransactionId, Transaction> transactions = |
218 | + this.<TransactionId, Transaction>consistentMapBuilder() | ||
219 | + .withName("onos-transactions") | ||
220 | + .withSerializer(Serializer.using(KryoNamespaces.API, | ||
221 | + MapUpdate.class, | ||
222 | + MapUpdate.Type.class, | ||
223 | + Transaction.class, | ||
224 | + Transaction.State.class)) | ||
225 | + .buildAsyncMap(); | ||
226 | + | ||
227 | + transactionManager = new TransactionManager(partitionedDatabase, transactions); | ||
216 | partitionedDatabase.setTransactionManager(transactionManager); | 228 | partitionedDatabase.setTransactionManager(transactionManager); |
217 | 229 | ||
218 | log.info("Started"); | 230 | log.info("Started"); |
... | @@ -238,7 +250,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -238,7 +250,9 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
238 | 250 | ||
239 | @Override | 251 | @Override |
240 | public TransactionContextBuilder transactionContextBuilder() { | 252 | public TransactionContextBuilder transactionContextBuilder() { |
241 | - return new DefaultTransactionContextBuilder(this, transactionIdGenerator.getNewId()); | 253 | + return new DefaultTransactionContextBuilder(this::consistentMapBuilder, |
254 | + transactionManager::execute, | ||
255 | + transactionIdGenerator.get()); | ||
242 | } | 256 | } |
243 | 257 | ||
244 | @Override | 258 | @Override |
... | @@ -385,8 +399,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -385,8 +399,8 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
385 | } | 399 | } |
386 | 400 | ||
387 | @Override | 401 | @Override |
388 | - public Collection<Transaction> getTransactions() { | 402 | + public Collection<TransactionId> getPendingTransactions() { |
389 | - return complete(transactionManager.getTransactions()); | 403 | + return complete(transactionManager.getPendingTransactionIds()); |
390 | } | 404 | } |
391 | 405 | ||
392 | private static <T> T complete(CompletableFuture<T> future) { | 406 | private static <T> T complete(CompletableFuture<T> future) { |
... | @@ -402,11 +416,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { | ... | @@ -402,11 +416,6 @@ public class DatabaseManager implements StorageService, StorageAdminService { |
402 | } | 416 | } |
403 | } | 417 | } |
404 | 418 | ||
405 | - @Override | ||
406 | - public void redriveTransactions() { | ||
407 | - getTransactions().stream().forEach(transactionManager::execute); | ||
408 | - } | ||
409 | - | ||
410 | protected <K, V> DefaultAsyncConsistentMap<K, V> registerMap(DefaultAsyncConsistentMap<K, V> map) { | 419 | protected <K, V> DefaultAsyncConsistentMap<K, V> registerMap(DefaultAsyncConsistentMap<K, V> map) { |
411 | maps.put(map.name(), map); | 420 | maps.put(map.name(), map); |
412 | if (map.applicationId() != null) { | 421 | if (map.applicationId() != null) { | ... | ... |
... | @@ -17,7 +17,6 @@ | ... | @@ -17,7 +17,6 @@ |
17 | package org.onosproject.store.primitives.impl; | 17 | package org.onosproject.store.primitives.impl; |
18 | 18 | ||
19 | import org.onlab.util.Match; | 19 | import org.onlab.util.Match; |
20 | -import org.onosproject.store.service.Transaction; | ||
21 | import org.onosproject.store.service.Versioned; | 20 | import org.onosproject.store.service.Versioned; |
22 | 21 | ||
23 | import java.util.Collection; | 22 | import java.util.Collection; | ... | ... |
... | @@ -21,10 +21,10 @@ import java.nio.ByteBuffer; | ... | @@ -21,10 +21,10 @@ import java.nio.ByteBuffer; |
21 | import org.onlab.util.KryoNamespace; | 21 | import org.onlab.util.KryoNamespace; |
22 | import org.onlab.util.Match; | 22 | import org.onlab.util.Match; |
23 | import org.onosproject.cluster.NodeId; | 23 | import org.onosproject.cluster.NodeId; |
24 | +import org.onosproject.store.primitives.TransactionId; | ||
25 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; | ||
24 | import org.onosproject.store.serializers.KryoNamespaces; | 26 | import org.onosproject.store.serializers.KryoNamespaces; |
25 | import org.onosproject.store.serializers.KryoSerializer; | 27 | import org.onosproject.store.serializers.KryoSerializer; |
26 | -import org.onosproject.store.service.DatabaseUpdate; | ||
27 | -import org.onosproject.store.service.Transaction; | ||
28 | import org.onosproject.store.service.Versioned; | 28 | import org.onosproject.store.service.Versioned; |
29 | 29 | ||
30 | import net.kuujo.copycat.cluster.internal.MemberInfo; | 30 | import net.kuujo.copycat.cluster.internal.MemberInfo; |
... | @@ -69,13 +69,14 @@ public class DatabaseSerializer extends SerializerConfig { | ... | @@ -69,13 +69,14 @@ public class DatabaseSerializer extends SerializerConfig { |
69 | private static final KryoNamespace ONOS_STORE = KryoNamespace.newBuilder() | 69 | private static final KryoNamespace ONOS_STORE = KryoNamespace.newBuilder() |
70 | .nextId(KryoNamespace.FLOATING_ID) | 70 | .nextId(KryoNamespace.FLOATING_ID) |
71 | .register(Versioned.class) | 71 | .register(Versioned.class) |
72 | - .register(DatabaseUpdate.class) | 72 | + .register(MapUpdate.class) |
73 | - .register(DatabaseUpdate.Type.class) | 73 | + .register(MapUpdate.Type.class) |
74 | .register(Result.class) | 74 | .register(Result.class) |
75 | .register(UpdateResult.class) | 75 | .register(UpdateResult.class) |
76 | .register(Result.Status.class) | 76 | .register(Result.Status.class) |
77 | - .register(DefaultTransaction.class) | 77 | + .register(Transaction.class) |
78 | .register(Transaction.State.class) | 78 | .register(Transaction.State.class) |
79 | + .register(TransactionId.class) | ||
79 | .register(org.onosproject.store.primitives.impl.CommitResponse.class) | 80 | .register(org.onosproject.store.primitives.impl.CommitResponse.class) |
80 | .register(Match.class) | 81 | .register(Match.class) |
81 | .register(NodeId.class) | 82 | .register(NodeId.class) | ... | ... |
... | @@ -22,7 +22,6 @@ import net.kuujo.copycat.state.Query; | ... | @@ -22,7 +22,6 @@ import net.kuujo.copycat.state.Query; |
22 | import net.kuujo.copycat.state.StateContext; | 22 | import net.kuujo.copycat.state.StateContext; |
23 | 23 | ||
24 | import org.onlab.util.Match; | 24 | import org.onlab.util.Match; |
25 | -import org.onosproject.store.service.Transaction; | ||
26 | import org.onosproject.store.service.Versioned; | 25 | import org.onosproject.store.service.Versioned; |
27 | 26 | ||
28 | import java.util.Collection; | 27 | import java.util.Collection; | ... | ... |
... | @@ -26,7 +26,6 @@ import net.kuujo.copycat.util.concurrent.Futures; | ... | @@ -26,7 +26,6 @@ import net.kuujo.copycat.util.concurrent.Futures; |
26 | import net.kuujo.copycat.util.function.TriConsumer; | 26 | import net.kuujo.copycat.util.function.TriConsumer; |
27 | 27 | ||
28 | import org.onlab.util.Match; | 28 | import org.onlab.util.Match; |
29 | -import org.onosproject.store.service.Transaction; | ||
30 | import org.onosproject.store.service.Versioned; | 29 | import org.onosproject.store.service.Versioned; |
31 | 30 | ||
32 | import java.util.Collection; | 31 | import java.util.Collection; | ... | ... |
... | @@ -26,8 +26,8 @@ import net.kuujo.copycat.state.Initializer; | ... | @@ -26,8 +26,8 @@ import net.kuujo.copycat.state.Initializer; |
26 | import net.kuujo.copycat.state.StateContext; | 26 | import net.kuujo.copycat.state.StateContext; |
27 | 27 | ||
28 | import org.onlab.util.Match; | 28 | import org.onlab.util.Match; |
29 | -import org.onosproject.store.service.DatabaseUpdate; | 29 | +import org.onosproject.store.primitives.TransactionId; |
30 | -import org.onosproject.store.service.Transaction; | 30 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; |
31 | import org.onosproject.store.service.Versioned; | 31 | import org.onosproject.store.service.Versioned; |
32 | 32 | ||
33 | import java.util.Arrays; | 33 | import java.util.Arrays; |
... | @@ -278,7 +278,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -278,7 +278,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
278 | return queues.computeIfAbsent(queueName, name -> new LinkedList<>()); | 278 | return queues.computeIfAbsent(queueName, name -> new LinkedList<>()); |
279 | } | 279 | } |
280 | 280 | ||
281 | - private boolean isUpdatePossible(DatabaseUpdate update) { | 281 | + private boolean isUpdatePossible(MapUpdate<String, byte[]> update) { |
282 | Versioned<byte[]> existingEntry = mapGet(update.mapName(), update.key()); | 282 | Versioned<byte[]> existingEntry = mapGet(update.mapName(), update.key()); |
283 | switch (update.type()) { | 283 | switch (update.type()) { |
284 | case PUT: | 284 | case PUT: |
... | @@ -299,7 +299,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -299,7 +299,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
299 | } | 299 | } |
300 | } | 300 | } |
301 | 301 | ||
302 | - private void doProvisionalUpdate(DatabaseUpdate update, long transactionId) { | 302 | + private void doProvisionalUpdate(MapUpdate<String, byte[]> update, TransactionId transactionId) { |
303 | Map<String, Update> lockMap = getLockMap(update.mapName()); | 303 | Map<String, Update> lockMap = getLockMap(update.mapName()); |
304 | switch (update.type()) { | 304 | switch (update.type()) { |
305 | case PUT: | 305 | case PUT: |
... | @@ -318,7 +318,8 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -318,7 +318,8 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
318 | } | 318 | } |
319 | } | 319 | } |
320 | 320 | ||
321 | - private UpdateResult<String, byte[]> commitProvisionalUpdate(DatabaseUpdate update, long transactionId) { | 321 | + private UpdateResult<String, byte[]> commitProvisionalUpdate( |
322 | + MapUpdate<String, byte[]> update, TransactionId transactionId) { | ||
322 | String mapName = update.mapName(); | 323 | String mapName = update.mapName(); |
323 | String key = update.key(); | 324 | String key = update.key(); |
324 | Update provisionalUpdate = getLockMap(mapName).get(key); | 325 | Update provisionalUpdate = getLockMap(mapName).get(key); |
... | @@ -330,7 +331,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -330,7 +331,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
330 | return mapUpdate(mapName, key, Match.any(), Match.any(), provisionalUpdate.value()).value(); | 331 | return mapUpdate(mapName, key, Match.any(), Match.any(), provisionalUpdate.value()).value(); |
331 | } | 332 | } |
332 | 333 | ||
333 | - private void undoProvisionalUpdate(DatabaseUpdate update, long transactionId) { | 334 | + private void undoProvisionalUpdate(MapUpdate<String, byte[]> update, TransactionId transactionId) { |
334 | String mapName = update.mapName(); | 335 | String mapName = update.mapName(); |
335 | String key = update.key(); | 336 | String key = update.key(); |
336 | Update provisionalUpdate = getLockMap(mapName).get(key); | 337 | Update provisionalUpdate = getLockMap(mapName).get(key); |
... | @@ -342,7 +343,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -342,7 +343,7 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
342 | } | 343 | } |
343 | } | 344 | } |
344 | 345 | ||
345 | - private boolean isLockedByAnotherTransaction(String mapName, String key, long transactionId) { | 346 | + private boolean isLockedByAnotherTransaction(String mapName, String key, TransactionId transactionId) { |
346 | Update update = getLockMap(mapName).get(key); | 347 | Update update = getLockMap(mapName).get(key); |
347 | return update != null && !Objects.equal(transactionId, update.transactionId()); | 348 | return update != null && !Objects.equal(transactionId, update.transactionId()); |
348 | } | 349 | } |
... | @@ -356,15 +357,15 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { | ... | @@ -356,15 +357,15 @@ public class DefaultDatabaseState implements DatabaseState<String, byte[]> { |
356 | } | 357 | } |
357 | 358 | ||
358 | private class Update { | 359 | private class Update { |
359 | - private final long transactionId; | 360 | + private final TransactionId transactionId; |
360 | private final byte[] value; | 361 | private final byte[] value; |
361 | 362 | ||
362 | - public Update(long txId, byte[] value) { | 363 | + public Update(TransactionId txId, byte[] value) { |
363 | this.transactionId = txId; | 364 | this.transactionId = txId; |
364 | this.value = value; | 365 | this.value = value; |
365 | } | 366 | } |
366 | 367 | ||
367 | - public long transactionId() { | 368 | + public TransactionId transactionId() { |
368 | return this.transactionId; | 369 | return this.transactionId; |
369 | } | 370 | } |
370 | 371 | ... | ... |
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onosproject.store.primitives.impl; | ||
17 | - | ||
18 | -import java.util.List; | ||
19 | - | ||
20 | -import org.onosproject.store.service.DatabaseUpdate; | ||
21 | -import org.onosproject.store.service.Transaction; | ||
22 | - | ||
23 | -import com.google.common.collect.ImmutableList; | ||
24 | - | ||
25 | -/** | ||
26 | - * A Default transaction implementation. | ||
27 | - */ | ||
28 | -public class DefaultTransaction implements Transaction { | ||
29 | - | ||
30 | - private final long transactionId; | ||
31 | - private final List<DatabaseUpdate> updates; | ||
32 | - private final State state; | ||
33 | - private final long lastUpdated; | ||
34 | - | ||
35 | - public DefaultTransaction(long transactionId, List<DatabaseUpdate> updates) { | ||
36 | - this(transactionId, updates, State.PREPARING, System.currentTimeMillis()); | ||
37 | - } | ||
38 | - | ||
39 | - private DefaultTransaction(long transactionId, List<DatabaseUpdate> updates, State state, long lastUpdated) { | ||
40 | - this.transactionId = transactionId; | ||
41 | - this.updates = ImmutableList.copyOf(updates); | ||
42 | - this.state = state; | ||
43 | - this.lastUpdated = lastUpdated; | ||
44 | - } | ||
45 | - | ||
46 | - @Override | ||
47 | - public long id() { | ||
48 | - return transactionId; | ||
49 | - } | ||
50 | - | ||
51 | - @Override | ||
52 | - public List<DatabaseUpdate> updates() { | ||
53 | - return updates; | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | - public State state() { | ||
58 | - return state; | ||
59 | - } | ||
60 | - | ||
61 | - @Override | ||
62 | - public Transaction transition(State newState) { | ||
63 | - return new DefaultTransaction(transactionId, updates, newState, System.currentTimeMillis()); | ||
64 | - } | ||
65 | - | ||
66 | - @Override | ||
67 | - public long lastUpdated() { | ||
68 | - return lastUpdated; | ||
69 | - } | ||
70 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -18,14 +18,17 @@ package org.onosproject.store.primitives.impl; | ... | @@ -18,14 +18,17 @@ package org.onosproject.store.primitives.impl; |
18 | 18 | ||
19 | import java.util.List; | 19 | import java.util.List; |
20 | import java.util.Map; | 20 | import java.util.Map; |
21 | +import java.util.concurrent.CompletableFuture; | ||
22 | +import java.util.function.Function; | ||
21 | import java.util.function.Supplier; | 23 | import java.util.function.Supplier; |
22 | 24 | ||
23 | import static com.google.common.base.Preconditions.*; | 25 | import static com.google.common.base.Preconditions.*; |
24 | 26 | ||
27 | +import org.onosproject.store.primitives.TransactionId; | ||
28 | +import org.onosproject.store.primitives.resources.impl.CommitResult; | ||
29 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; | ||
25 | import org.onosproject.store.service.ConsistentMapBuilder; | 30 | import org.onosproject.store.service.ConsistentMapBuilder; |
26 | -import org.onosproject.store.service.DatabaseUpdate; | ||
27 | import org.onosproject.store.service.Serializer; | 31 | import org.onosproject.store.service.Serializer; |
28 | -import org.onosproject.store.service.Transaction; | ||
29 | import org.onosproject.store.service.TransactionContext; | 32 | import org.onosproject.store.service.TransactionContext; |
30 | import org.onosproject.store.service.TransactionalMap; | 33 | import org.onosproject.store.service.TransactionalMap; |
31 | 34 | ||
... | @@ -44,20 +47,20 @@ public class DefaultTransactionContext implements TransactionContext { | ... | @@ -44,20 +47,20 @@ public class DefaultTransactionContext implements TransactionContext { |
44 | @SuppressWarnings("rawtypes") | 47 | @SuppressWarnings("rawtypes") |
45 | private final Map<String, DefaultTransactionalMap> txMaps = Maps.newConcurrentMap(); | 48 | private final Map<String, DefaultTransactionalMap> txMaps = Maps.newConcurrentMap(); |
46 | private boolean isOpen = false; | 49 | private boolean isOpen = false; |
47 | - private final Database database; | 50 | + private final Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter; |
48 | - private final long transactionId; | 51 | + private final TransactionId transactionId; |
49 | private final Supplier<ConsistentMapBuilder> mapBuilderSupplier; | 52 | private final Supplier<ConsistentMapBuilder> mapBuilderSupplier; |
50 | 53 | ||
51 | - public DefaultTransactionContext(long transactionId, | 54 | + public DefaultTransactionContext(TransactionId transactionId, |
52 | - Database database, | 55 | + Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter, |
53 | Supplier<ConsistentMapBuilder> mapBuilderSupplier) { | 56 | Supplier<ConsistentMapBuilder> mapBuilderSupplier) { |
54 | this.transactionId = transactionId; | 57 | this.transactionId = transactionId; |
55 | - this.database = checkNotNull(database); | 58 | + this.transactionCommitter = checkNotNull(transactionCommitter); |
56 | this.mapBuilderSupplier = checkNotNull(mapBuilderSupplier); | 59 | this.mapBuilderSupplier = checkNotNull(mapBuilderSupplier); |
57 | } | 60 | } |
58 | 61 | ||
59 | @Override | 62 | @Override |
60 | - public long transactionId() { | 63 | + public TransactionId transactionId() { |
61 | return transactionId; | 64 | return transactionId; |
62 | } | 65 | } |
63 | 66 | ||
... | @@ -91,13 +94,13 @@ public class DefaultTransactionContext implements TransactionContext { | ... | @@ -91,13 +94,13 @@ public class DefaultTransactionContext implements TransactionContext { |
91 | public boolean commit() { | 94 | public boolean commit() { |
92 | // TODO: rework commit implementation to be more intuitive | 95 | // TODO: rework commit implementation to be more intuitive |
93 | checkState(isOpen, TX_NOT_OPEN_ERROR); | 96 | checkState(isOpen, TX_NOT_OPEN_ERROR); |
94 | - CommitResponse response = null; | 97 | + CommitResult result = null; |
95 | try { | 98 | try { |
96 | - List<DatabaseUpdate> updates = Lists.newLinkedList(); | 99 | + List<MapUpdate<String, byte[]>> updates = Lists.newLinkedList(); |
97 | - txMaps.values().forEach(m -> updates.addAll(m.prepareDatabaseUpdates())); | 100 | + txMaps.values().forEach(m -> updates.addAll(m.toMapUpdates())); |
98 | - Transaction transaction = new DefaultTransaction(transactionId, updates); | 101 | + Transaction transaction = new Transaction(transactionId, updates); |
99 | - response = Futures.getUnchecked(database.prepareAndCommit(transaction)); | 102 | + result = Futures.getUnchecked(transactionCommitter.apply(transaction)); |
100 | - return response.success(); | 103 | + return result == CommitResult.OK; |
101 | } catch (Exception e) { | 104 | } catch (Exception e) { |
102 | abort(); | 105 | abort(); |
103 | return false; | 106 | return false; |
... | @@ -128,4 +131,9 @@ public class DefaultTransactionContext implements TransactionContext { | ... | @@ -128,4 +131,9 @@ public class DefaultTransactionContext implements TransactionContext { |
128 | }); | 131 | }); |
129 | return s.toString(); | 132 | return s.toString(); |
130 | } | 133 | } |
134 | + | ||
135 | + @Override | ||
136 | + public String name() { | ||
137 | + return transactionId.toString(); | ||
138 | + } | ||
131 | } | 139 | } | ... | ... |
... | @@ -15,6 +15,13 @@ | ... | @@ -15,6 +15,13 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.primitives.impl; | 16 | package org.onosproject.store.primitives.impl; |
17 | 17 | ||
18 | +import java.util.concurrent.CompletableFuture; | ||
19 | +import java.util.function.Function; | ||
20 | +import java.util.function.Supplier; | ||
21 | + | ||
22 | +import org.onosproject.store.primitives.TransactionId; | ||
23 | +import org.onosproject.store.primitives.resources.impl.CommitResult; | ||
24 | +import org.onosproject.store.service.ConsistentMapBuilder; | ||
18 | import org.onosproject.store.service.TransactionContext; | 25 | import org.onosproject.store.service.TransactionContext; |
19 | import org.onosproject.store.service.TransactionContextBuilder; | 26 | import org.onosproject.store.service.TransactionContextBuilder; |
20 | 27 | ||
... | @@ -22,29 +29,28 @@ import org.onosproject.store.service.TransactionContextBuilder; | ... | @@ -22,29 +29,28 @@ import org.onosproject.store.service.TransactionContextBuilder; |
22 | * The default implementation of a transaction context builder. This builder | 29 | * The default implementation of a transaction context builder. This builder |
23 | * generates a {@link DefaultTransactionContext}. | 30 | * generates a {@link DefaultTransactionContext}. |
24 | */ | 31 | */ |
25 | -public class DefaultTransactionContextBuilder implements TransactionContextBuilder { | 32 | +public class DefaultTransactionContextBuilder extends TransactionContextBuilder { |
26 | 33 | ||
27 | - private boolean partitionsEnabled = true; | 34 | + private final Supplier<ConsistentMapBuilder> mapBuilderSupplier; |
28 | - private final DatabaseManager manager; | 35 | + private final Function<Transaction, CompletableFuture<CommitResult>> transactionCommitter; |
29 | - private final long transactionId; | 36 | + private final TransactionId transactionId; |
30 | 37 | ||
31 | - public DefaultTransactionContextBuilder(DatabaseManager manager, long transactionId) { | 38 | + public DefaultTransactionContextBuilder(Supplier<ConsistentMapBuilder> mapBuilderSupplier, |
32 | - this.manager = manager; | 39 | + Function<Transaction, CompletableFuture<CommitResult>> transactionCommiter, |
40 | + TransactionId transactionId) { | ||
41 | + this.mapBuilderSupplier = mapBuilderSupplier; | ||
42 | + this.transactionCommitter = transactionCommiter; | ||
33 | this.transactionId = transactionId; | 43 | this.transactionId = transactionId; |
34 | } | 44 | } |
35 | 45 | ||
36 | @Override | 46 | @Override |
37 | - public TransactionContextBuilder withPartitionsDisabled() { | ||
38 | - partitionsEnabled = false; | ||
39 | - return this; | ||
40 | - } | ||
41 | - | ||
42 | - @Override | ||
43 | public TransactionContext build() { | 47 | public TransactionContext build() { |
44 | - return new DefaultTransactionContext( | 48 | + return new DefaultTransactionContext(transactionId, transactionCommitter, () -> { |
45 | - transactionId, | 49 | + ConsistentMapBuilder mapBuilder = mapBuilderSupplier.get(); |
46 | - partitionsEnabled ? manager.partitionedDatabase : manager.inMemoryDatabase, | 50 | + if (partitionsDisabled()) { |
47 | - () -> partitionsEnabled ? manager.consistentMapBuilder() | 51 | + mapBuilder = mapBuilder.withPartitionsDisabled(); |
48 | - : manager.consistentMapBuilder().withPartitionsDisabled()); | 52 | + } |
53 | + return mapBuilder; | ||
54 | + }); | ||
49 | } | 55 | } |
50 | } | 56 | } | ... | ... |
... | @@ -21,8 +21,8 @@ import java.util.Map; | ... | @@ -21,8 +21,8 @@ import java.util.Map; |
21 | import java.util.Set; | 21 | import java.util.Set; |
22 | 22 | ||
23 | import org.onlab.util.HexString; | 23 | import org.onlab.util.HexString; |
24 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; | ||
24 | import org.onosproject.store.service.ConsistentMap; | 25 | import org.onosproject.store.service.ConsistentMap; |
25 | -import org.onosproject.store.service.DatabaseUpdate; | ||
26 | import org.onosproject.store.service.Serializer; | 26 | import org.onosproject.store.service.Serializer; |
27 | import org.onosproject.store.service.TransactionContext; | 27 | import org.onosproject.store.service.TransactionContext; |
28 | import org.onosproject.store.service.TransactionalMap; | 28 | import org.onosproject.store.service.TransactionalMap; |
... | @@ -159,14 +159,14 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { | ... | @@ -159,14 +159,14 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { |
159 | return latest; | 159 | return latest; |
160 | } | 160 | } |
161 | 161 | ||
162 | - protected List<DatabaseUpdate> prepareDatabaseUpdates() { | 162 | + protected List<MapUpdate<String, byte[]>> toMapUpdates() { |
163 | - List<DatabaseUpdate> updates = Lists.newLinkedList(); | 163 | + List<MapUpdate<String, byte[]>> updates = Lists.newLinkedList(); |
164 | deleteSet.forEach(key -> { | 164 | deleteSet.forEach(key -> { |
165 | Versioned<V> original = readCache.get(key); | 165 | Versioned<V> original = readCache.get(key); |
166 | if (original != null) { | 166 | if (original != null) { |
167 | - updates.add(DatabaseUpdate.newBuilder() | 167 | + updates.add(MapUpdate.<String, byte[]>newBuilder() |
168 | .withMapName(name) | 168 | .withMapName(name) |
169 | - .withType(DatabaseUpdate.Type.REMOVE_IF_VERSION_MATCH) | 169 | + .withType(MapUpdate.Type.REMOVE_IF_VERSION_MATCH) |
170 | .withKey(keyCache.getUnchecked(key)) | 170 | .withKey(keyCache.getUnchecked(key)) |
171 | .withCurrentVersion(original.version()) | 171 | .withCurrentVersion(original.version()) |
172 | .build()); | 172 | .build()); |
... | @@ -175,16 +175,16 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { | ... | @@ -175,16 +175,16 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { |
175 | writeCache.forEach((key, value) -> { | 175 | writeCache.forEach((key, value) -> { |
176 | Versioned<V> original = readCache.get(key); | 176 | Versioned<V> original = readCache.get(key); |
177 | if (original == null) { | 177 | if (original == null) { |
178 | - updates.add(DatabaseUpdate.newBuilder() | 178 | + updates.add(MapUpdate.<String, byte[]>newBuilder() |
179 | .withMapName(name) | 179 | .withMapName(name) |
180 | - .withType(DatabaseUpdate.Type.PUT_IF_ABSENT) | 180 | + .withType(MapUpdate.Type.PUT_IF_ABSENT) |
181 | .withKey(keyCache.getUnchecked(key)) | 181 | .withKey(keyCache.getUnchecked(key)) |
182 | .withValue(serializer.encode(value)) | 182 | .withValue(serializer.encode(value)) |
183 | .build()); | 183 | .build()); |
184 | } else { | 184 | } else { |
185 | - updates.add(DatabaseUpdate.newBuilder() | 185 | + updates.add(MapUpdate.<String, byte[]>newBuilder() |
186 | .withMapName(name) | 186 | .withMapName(name) |
187 | - .withType(DatabaseUpdate.Type.PUT_IF_VERSION_MATCH) | 187 | + .withType(MapUpdate.Type.PUT_IF_VERSION_MATCH) |
188 | .withKey(keyCache.getUnchecked(key)) | 188 | .withKey(keyCache.getUnchecked(key)) |
189 | .withCurrentVersion(original.version()) | 189 | .withCurrentVersion(original.version()) |
190 | .withValue(serializer.encode(value)) | 190 | .withValue(serializer.encode(value)) |
... | @@ -199,7 +199,7 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { | ... | @@ -199,7 +199,7 @@ public class DefaultTransactionalMap<K, V> implements TransactionalMap<K, V> { |
199 | public String toString() { | 199 | public String toString() { |
200 | return MoreObjects.toStringHelper(this) | 200 | return MoreObjects.toStringHelper(this) |
201 | .add("backingMap", backingMap) | 201 | .add("backingMap", backingMap) |
202 | - .add("updates", prepareDatabaseUpdates()) | 202 | + .add("updates", toMapUpdates()) |
203 | .toString(); | 203 | .toString(); |
204 | } | 204 | } |
205 | 205 | ... | ... |
... | @@ -26,8 +26,8 @@ import net.kuujo.copycat.cluster.Cluster; | ... | @@ -26,8 +26,8 @@ import net.kuujo.copycat.cluster.Cluster; |
26 | import net.kuujo.copycat.resource.ResourceState; | 26 | import net.kuujo.copycat.resource.ResourceState; |
27 | 27 | ||
28 | import org.onlab.util.Match; | 28 | import org.onlab.util.Match; |
29 | -import org.onosproject.store.service.DatabaseUpdate; | 29 | +import org.onosproject.store.primitives.resources.impl.CommitResult; |
30 | -import org.onosproject.store.service.Transaction; | 30 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; |
31 | import org.onosproject.store.service.Versioned; | 31 | import org.onosproject.store.service.Versioned; |
32 | 32 | ||
33 | import java.util.Collection; | 33 | import java.util.Collection; |
... | @@ -273,7 +273,9 @@ public class PartitionedDatabase implements Database { | ... | @@ -273,7 +273,9 @@ public class PartitionedDatabase implements Database { |
273 | if (transactionManager == null) { | 273 | if (transactionManager == null) { |
274 | throw new IllegalStateException("TransactionManager is not initialized"); | 274 | throw new IllegalStateException("TransactionManager is not initialized"); |
275 | } | 275 | } |
276 | - return transactionManager.execute(transaction); | 276 | + return transactionManager.execute(transaction) |
277 | + .thenApply(r -> r == CommitResult.OK | ||
278 | + ? CommitResponse.success(ImmutableList.of()) : CommitResponse.failure()); | ||
277 | } | 279 | } |
278 | } | 280 | } |
279 | 281 | ||
... | @@ -373,15 +375,15 @@ public class PartitionedDatabase implements Database { | ... | @@ -373,15 +375,15 @@ public class PartitionedDatabase implements Database { |
373 | 375 | ||
374 | private Map<Database, Transaction> createSubTransactions( | 376 | private Map<Database, Transaction> createSubTransactions( |
375 | Transaction transaction) { | 377 | Transaction transaction) { |
376 | - Map<Database, List<DatabaseUpdate>> perPartitionUpdates = Maps.newHashMap(); | 378 | + Map<Database, List<MapUpdate<String, byte[]>>> perPartitionUpdates = Maps.newHashMap(); |
377 | - for (DatabaseUpdate update : transaction.updates()) { | 379 | + for (MapUpdate<String, byte[]> update : transaction.updates()) { |
378 | Database partition = partitioner.getPartition(update.mapName(), update.key()); | 380 | Database partition = partitioner.getPartition(update.mapName(), update.key()); |
379 | - List<DatabaseUpdate> partitionUpdates = | 381 | + List<MapUpdate<String, byte[]>> partitionUpdates = |
380 | perPartitionUpdates.computeIfAbsent(partition, k -> Lists.newLinkedList()); | 382 | perPartitionUpdates.computeIfAbsent(partition, k -> Lists.newLinkedList()); |
381 | partitionUpdates.add(update); | 383 | partitionUpdates.add(update); |
382 | } | 384 | } |
383 | Map<Database, Transaction> subTransactions = Maps.newHashMap(); | 385 | Map<Database, Transaction> subTransactions = Maps.newHashMap(); |
384 | - perPartitionUpdates.forEach((k, v) -> subTransactions.put(k, new DefaultTransaction(transaction.id(), v))); | 386 | + perPartitionUpdates.forEach((k, v) -> subTransactions.put(k, new Transaction(transaction.id(), v))); |
385 | return subTransactions; | 387 | return subTransactions; |
386 | } | 388 | } |
387 | 389 | ... | ... |
... | @@ -13,14 +13,20 @@ | ... | @@ -13,14 +13,20 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onosproject.store.service; | 16 | +package org.onosproject.store.primitives.impl; |
17 | 17 | ||
18 | import java.util.List; | 18 | import java.util.List; |
19 | 19 | ||
20 | +import org.onosproject.store.primitives.TransactionId; | ||
21 | +import org.onosproject.store.primitives.resources.impl.MapUpdate; | ||
22 | + | ||
23 | +import com.google.common.base.MoreObjects; | ||
24 | +import com.google.common.collect.ImmutableList; | ||
25 | + | ||
20 | /** | 26 | /** |
21 | * An immutable transaction object. | 27 | * An immutable transaction object. |
22 | */ | 28 | */ |
23 | -public interface Transaction { | 29 | +public class Transaction { |
24 | 30 | ||
25 | enum State { | 31 | enum State { |
26 | /** | 32 | /** |
... | @@ -55,48 +61,44 @@ public interface Transaction { | ... | @@ -55,48 +61,44 @@ public interface Transaction { |
55 | ROLLEDBACK | 61 | ROLLEDBACK |
56 | } | 62 | } |
57 | 63 | ||
58 | - /** | 64 | + private final TransactionId transactionId; |
59 | - * Returns the transaction Id. | 65 | + private final List<MapUpdate<String, byte[]>> updates; |
60 | - * | 66 | + private final State state; |
61 | - * @return transaction id | ||
62 | - */ | ||
63 | - long id(); | ||
64 | 67 | ||
65 | - /** | 68 | + public Transaction(TransactionId transactionId, List<MapUpdate<String, byte[]>> updates) { |
66 | - * Returns the list of updates that are part of this transaction. | 69 | + this(transactionId, updates, State.PREPARING); |
67 | - * | 70 | + } |
68 | - * @return list of database updates | ||
69 | - */ | ||
70 | - List<DatabaseUpdate> updates(); | ||
71 | 71 | ||
72 | - /** | 72 | + private Transaction(TransactionId transactionId, |
73 | - * Returns the current state of this transaction. | 73 | + List<MapUpdate<String, byte[]>> updates, |
74 | - * | 74 | + State state) { |
75 | - * @return transaction state | 75 | + this.transactionId = transactionId; |
76 | - */ | 76 | + this.updates = ImmutableList.copyOf(updates); |
77 | - State state(); | 77 | + this.state = state; |
78 | + } | ||
78 | 79 | ||
79 | - /** | 80 | + public TransactionId id() { |
80 | - * Returns true if this transaction has completed execution. | 81 | + return transactionId; |
81 | - * | ||
82 | - * @return true is yes, false otherwise | ||
83 | - */ | ||
84 | - default boolean isDone() { | ||
85 | - return state() == State.COMMITTED || state() == State.ROLLEDBACK; | ||
86 | } | 82 | } |
87 | 83 | ||
88 | - /** | 84 | + public List<MapUpdate<String, byte[]>> updates() { |
89 | - * Returns a new transaction that is created by transitioning this one to the specified state. | 85 | + return updates; |
90 | - * | 86 | + } |
91 | - * @param newState destination state | ||
92 | - * @return a new transaction instance similar to the current one but its state set to specified state | ||
93 | - */ | ||
94 | - Transaction transition(State newState); | ||
95 | 87 | ||
96 | - /** | 88 | + public State state() { |
97 | - * Returns the system time when the transaction was last updated. | 89 | + return state; |
98 | - * | 90 | + } |
99 | - * @return last update time | 91 | + |
100 | - */ | 92 | + public Transaction transition(State newState) { |
101 | - long lastUpdated(); | 93 | + return new Transaction(transactionId, updates, newState); |
94 | + } | ||
95 | + | ||
96 | + @Override | ||
97 | + public String toString() { | ||
98 | + return MoreObjects.toStringHelper(getClass()) | ||
99 | + .add("transactionId", transactionId) | ||
100 | + .add("updates", updates) | ||
101 | + .add("state", state) | ||
102 | + .toString(); | ||
103 | + } | ||
102 | } | 104 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -17,87 +17,62 @@ package org.onosproject.store.primitives.impl; | ... | @@ -17,87 +17,62 @@ package org.onosproject.store.primitives.impl; |
17 | 17 | ||
18 | import static com.google.common.base.Preconditions.checkNotNull; | 18 | import static com.google.common.base.Preconditions.checkNotNull; |
19 | 19 | ||
20 | -import java.util.Arrays; | ||
21 | import java.util.Collection; | 20 | import java.util.Collection; |
22 | import java.util.concurrent.CompletableFuture; | 21 | import java.util.concurrent.CompletableFuture; |
23 | import java.util.stream.Collectors; | 22 | import java.util.stream.Collectors; |
24 | 23 | ||
25 | -import org.onlab.util.KryoNamespace; | 24 | +import org.onosproject.store.primitives.TransactionId; |
26 | -import org.onosproject.store.serializers.KryoNamespaces; | 25 | +import org.onosproject.store.primitives.resources.impl.CommitResult; |
27 | import org.onosproject.store.service.AsyncConsistentMap; | 26 | import org.onosproject.store.service.AsyncConsistentMap; |
28 | -import org.onosproject.store.service.ConsistentMapBuilder; | ||
29 | -import org.onosproject.store.service.DatabaseUpdate; | ||
30 | -import org.onosproject.store.service.Serializer; | ||
31 | -import org.onosproject.store.service.Transaction; | ||
32 | -import org.onosproject.store.service.Versioned; | ||
33 | -import org.onosproject.store.service.Transaction.State; | ||
34 | 27 | ||
35 | -import com.google.common.collect.ImmutableList; | 28 | +import static org.onosproject.store.primitives.impl.Transaction.State.COMMITTED; |
29 | +import static org.onosproject.store.primitives.impl.Transaction.State.COMMITTING; | ||
30 | +import static org.onosproject.store.primitives.impl.Transaction.State.ROLLEDBACK; | ||
31 | +import static org.onosproject.store.primitives.impl.Transaction.State.ROLLINGBACK; | ||
36 | 32 | ||
37 | /** | 33 | /** |
38 | * Agent that runs the two phase commit protocol. | 34 | * Agent that runs the two phase commit protocol. |
39 | */ | 35 | */ |
40 | public class TransactionManager { | 36 | public class TransactionManager { |
41 | 37 | ||
42 | - private static final KryoNamespace KRYO_NAMESPACE = KryoNamespace.newBuilder() | ||
43 | - .register(KryoNamespaces.BASIC) | ||
44 | - .nextId(KryoNamespace.FLOATING_ID) | ||
45 | - .register(Versioned.class) | ||
46 | - .register(DatabaseUpdate.class) | ||
47 | - .register(DatabaseUpdate.Type.class) | ||
48 | - .register(DefaultTransaction.class) | ||
49 | - .register(Transaction.State.class) | ||
50 | - .build(); | ||
51 | - | ||
52 | - private final Serializer serializer = Serializer.using(Arrays.asList(KRYO_NAMESPACE)); | ||
53 | private final Database database; | 38 | private final Database database; |
54 | - private final AsyncConsistentMap<Long, Transaction> transactions; | 39 | + private final AsyncConsistentMap<TransactionId, Transaction> transactions; |
55 | 40 | ||
56 | - /** | 41 | + public TransactionManager(Database database, AsyncConsistentMap<TransactionId, Transaction> transactions) { |
57 | - * Constructs a new TransactionManager for the specified database instance. | ||
58 | - * | ||
59 | - * @param database database | ||
60 | - * @param mapBuilder builder for ConsistentMap instances | ||
61 | - */ | ||
62 | - public TransactionManager(Database database, ConsistentMapBuilder<Long, Transaction> mapBuilder) { | ||
63 | this.database = checkNotNull(database, "database cannot be null"); | 42 | this.database = checkNotNull(database, "database cannot be null"); |
64 | - this.transactions = mapBuilder.withName("onos-transactions") | 43 | + this.transactions = transactions; |
65 | - .withSerializer(serializer) | ||
66 | - .buildAsyncMap(); | ||
67 | } | 44 | } |
68 | 45 | ||
69 | /** | 46 | /** |
70 | * Executes the specified transaction by employing a two phase commit protocol. | 47 | * Executes the specified transaction by employing a two phase commit protocol. |
71 | * | 48 | * |
72 | * @param transaction transaction to commit | 49 | * @param transaction transaction to commit |
73 | - * @return transaction result. Result value true indicates a successful commit, false | 50 | + * @return transaction commit result |
74 | - * indicates abort | ||
75 | */ | 51 | */ |
76 | - public CompletableFuture<CommitResponse> execute(Transaction transaction) { | 52 | + public CompletableFuture<CommitResult> execute(Transaction transaction) { |
77 | // clean up if this transaction in already in a terminal state. | 53 | // clean up if this transaction in already in a terminal state. |
78 | - if (transaction.state() == Transaction.State.COMMITTED || | 54 | + if (transaction.state() == COMMITTED || transaction.state() == ROLLEDBACK) { |
79 | - transaction.state() == Transaction.State.ROLLEDBACK) { | 55 | + return transactions.remove(transaction.id()).thenApply(v -> CommitResult.OK); |
80 | - return transactions.remove(transaction.id()).thenApply(v -> CommitResponse.success(ImmutableList.of())); | 56 | + } else if (transaction.state() == COMMITTING) { |
81 | - } else if (transaction.state() == Transaction.State.COMMITTING) { | ||
82 | return commit(transaction); | 57 | return commit(transaction); |
83 | - } else if (transaction.state() == Transaction.State.ROLLINGBACK) { | 58 | + } else if (transaction.state() == ROLLINGBACK) { |
84 | - return rollback(transaction).thenApply(v -> CommitResponse.success(ImmutableList.of())); | 59 | + return rollback(transaction).thenApply(v -> CommitResult.FAILURE_TO_PREPARE); |
85 | } else { | 60 | } else { |
86 | return prepare(transaction).thenCompose(v -> v ? commit(transaction) : rollback(transaction)); | 61 | return prepare(transaction).thenCompose(v -> v ? commit(transaction) : rollback(transaction)); |
87 | } | 62 | } |
88 | } | 63 | } |
89 | 64 | ||
90 | - | ||
91 | /** | 65 | /** |
92 | - * Returns all transactions in the system. | 66 | + * Returns all pending transaction identifiers. |
93 | * | 67 | * |
94 | - * @return future for a collection of transactions | 68 | + * @return future for a collection of transaction identifiers. |
95 | */ | 69 | */ |
96 | - public CompletableFuture<Collection<Transaction>> getTransactions() { | 70 | + public CompletableFuture<Collection<TransactionId>> getPendingTransactionIds() { |
97 | - return transactions.values().thenApply(c -> { | 71 | + return transactions.values().thenApply(c -> c.stream() |
98 | - Collection<Transaction> txns = c.stream().map(v -> v.value()).collect(Collectors.toList()); | 72 | + .map(v -> v.value()) |
99 | - return txns; | 73 | + .filter(v -> v.state() != COMMITTED && v.state() != ROLLEDBACK) |
100 | - }); | 74 | + .map(Transaction::id) |
75 | + .collect(Collectors.toList())); | ||
101 | } | 76 | } |
102 | 77 | ||
103 | private CompletableFuture<Boolean> prepare(Transaction transaction) { | 78 | private CompletableFuture<Boolean> prepare(Transaction transaction) { |
... | @@ -105,22 +80,25 @@ public class TransactionManager { | ... | @@ -105,22 +80,25 @@ public class TransactionManager { |
105 | .thenCompose(v -> database.prepare(transaction)) | 80 | .thenCompose(v -> database.prepare(transaction)) |
106 | .thenCompose(status -> transactions.put( | 81 | .thenCompose(status -> transactions.put( |
107 | transaction.id(), | 82 | transaction.id(), |
108 | - transaction.transition(status ? State.COMMITTING : State.ROLLINGBACK)) | 83 | + transaction.transition(status ? COMMITTING : ROLLINGBACK)) |
109 | .thenApply(v -> status)); | 84 | .thenApply(v -> status)); |
110 | } | 85 | } |
111 | 86 | ||
112 | - private CompletableFuture<CommitResponse> commit(Transaction transaction) { | 87 | + private CompletableFuture<CommitResult> commit(Transaction transaction) { |
113 | return database.commit(transaction) | 88 | return database.commit(transaction) |
114 | - .whenComplete((r, e) -> transactions.put( | 89 | + .thenCompose(r -> { |
115 | - transaction.id(), | 90 | + if (r.success()) { |
116 | - transaction.transition(Transaction.State.COMMITTED))); | 91 | + return transactions.put(transaction.id(), transaction.transition(COMMITTED)) |
92 | + .thenApply(v -> CommitResult.OK); | ||
93 | + } else { | ||
94 | + return CompletableFuture.completedFuture(CommitResult.FAILURE_DURING_COMMIT); | ||
95 | + } | ||
96 | + }); | ||
117 | } | 97 | } |
118 | 98 | ||
119 | - private CompletableFuture<CommitResponse> rollback(Transaction transaction) { | 99 | + private CompletableFuture<CommitResult> rollback(Transaction transaction) { |
120 | return database.rollback(transaction) | 100 | return database.rollback(transaction) |
121 | - .thenCompose(v -> transactions.put( | 101 | + .thenCompose(v -> transactions.put(transaction.id(), transaction.transition(ROLLEDBACK))) |
122 | - transaction.id(), | 102 | + .thenApply(v -> CommitResult.FAILURE_TO_PREPARE); |
123 | - transaction.transition(Transaction.State.ROLLEDBACK))) | ||
124 | - .thenApply(v -> CommitResponse.failure()); | ||
125 | } | 103 | } |
126 | } | 104 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2016 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.store.primitives.impl; | ||
17 | + | ||
18 | +import java.util.concurrent.CompletableFuture; | ||
19 | + | ||
20 | +import org.onosproject.store.primitives.TransactionId; | ||
21 | +import org.onosproject.store.primitives.resources.impl.CommitResult; | ||
22 | +import org.onosproject.store.primitives.resources.impl.PrepareResult; | ||
23 | +import org.onosproject.store.primitives.resources.impl.RollbackResult; | ||
24 | + | ||
25 | +/** | ||
26 | + * Participant in a two-phase commit protocol. | ||
27 | + */ | ||
28 | +public interface TransactionParticipant { | ||
29 | + | ||
30 | + /** | ||
31 | + * Attempts to execute the prepare phase for the specified {@link Transaction transaction}. | ||
32 | + * @param transaction transaction | ||
33 | + * @return future for prepare result | ||
34 | + */ | ||
35 | + CompletableFuture<PrepareResult> prepare(Transaction transaction); | ||
36 | + | ||
37 | + /** | ||
38 | + * Attempts to execute the commit phase for previously prepared transaction. | ||
39 | + * @param transactionId transaction identifier | ||
40 | + * @return future for commit result | ||
41 | + */ | ||
42 | + CompletableFuture<CommitResult> commit(TransactionId transactionId); | ||
43 | + | ||
44 | + /** | ||
45 | + * Attempts to execute the rollback phase for previously prepared transaction. | ||
46 | + * @param transactionId transaction identifier | ||
47 | + * @return future for rollback result | ||
48 | + */ | ||
49 | + CompletableFuture<RollbackResult> rollback(TransactionId transactionId); | ||
50 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -31,6 +31,9 @@ import java.util.function.BiFunction; | ... | @@ -31,6 +31,9 @@ import java.util.function.BiFunction; |
31 | import java.util.function.Predicate; | 31 | import java.util.function.Predicate; |
32 | 32 | ||
33 | import org.onlab.util.Match; | 33 | import org.onlab.util.Match; |
34 | +import org.onosproject.store.primitives.TransactionId; | ||
35 | +import org.onosproject.store.primitives.impl.Transaction; | ||
36 | +import org.onosproject.store.primitives.impl.TransactionParticipant; | ||
34 | import org.onosproject.store.service.AsyncConsistentMap; | 37 | import org.onosproject.store.service.AsyncConsistentMap; |
35 | import org.onosproject.store.service.MapEvent; | 38 | import org.onosproject.store.service.MapEvent; |
36 | import org.onosproject.store.service.MapEventListener; | 39 | import org.onosproject.store.service.MapEventListener; |
... | @@ -43,7 +46,7 @@ import com.google.common.collect.Sets; | ... | @@ -43,7 +46,7 @@ import com.google.common.collect.Sets; |
43 | */ | 46 | */ |
44 | @ResourceTypeInfo(id = -151, stateMachine = AtomixConsistentMapState.class) | 47 | @ResourceTypeInfo(id = -151, stateMachine = AtomixConsistentMapState.class) |
45 | public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource.Options> | 48 | public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource.Options> |
46 | - implements AsyncConsistentMap<String, byte[]> { | 49 | + implements AsyncConsistentMap<String, byte[]>, TransactionParticipant { |
47 | 50 | ||
48 | private final Set<MapEventListener<String, byte[]>> mapEventListeners = Sets.newCopyOnWriteArraySet(); | 51 | private final Set<MapEventListener<String, byte[]>> mapEventListeners = Sets.newCopyOnWriteArraySet(); |
49 | 52 | ||
... | @@ -235,18 +238,6 @@ public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource. | ... | @@ -235,18 +238,6 @@ public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource. |
235 | }); | 238 | }); |
236 | } | 239 | } |
237 | 240 | ||
238 | - public CompletableFuture<PrepareResult> prepare(TransactionalMapUpdate<String, byte[]> update) { | ||
239 | - return submit(new AtomixConsistentMapCommands.TransactionPrepare(update)); | ||
240 | - } | ||
241 | - | ||
242 | - public CompletableFuture<CommitResult> commit(TransactionId transactionId) { | ||
243 | - return submit(new AtomixConsistentMapCommands.TransactionCommit(transactionId)); | ||
244 | - } | ||
245 | - | ||
246 | - public CompletableFuture<RollbackResult> rollback(TransactionId transactionId) { | ||
247 | - return submit(new AtomixConsistentMapCommands.TransactionRollback(transactionId)); | ||
248 | - } | ||
249 | - | ||
250 | @Override | 241 | @Override |
251 | public synchronized CompletableFuture<Void> addListener(MapEventListener<String, byte[]> listener) { | 242 | public synchronized CompletableFuture<Void> addListener(MapEventListener<String, byte[]> listener) { |
252 | if (!mapEventListeners.isEmpty()) { | 243 | if (!mapEventListeners.isEmpty()) { |
... | @@ -274,6 +265,21 @@ public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource. | ... | @@ -274,6 +265,21 @@ public class AtomixConsistentMap extends Resource<AtomixConsistentMap, Resource. |
274 | } | 265 | } |
275 | } | 266 | } |
276 | 267 | ||
268 | + @Override | ||
269 | + public CompletableFuture<PrepareResult> prepare(Transaction transaction) { | ||
270 | + return submit(new AtomixConsistentMapCommands.TransactionPrepare(transaction)); | ||
271 | + } | ||
272 | + | ||
273 | + @Override | ||
274 | + public CompletableFuture<CommitResult> commit(TransactionId transactionId) { | ||
275 | + return submit(new AtomixConsistentMapCommands.TransactionCommit(transactionId)); | ||
276 | + } | ||
277 | + | ||
278 | + @Override | ||
279 | + public CompletableFuture<RollbackResult> rollback(TransactionId transactionId) { | ||
280 | + return submit(new AtomixConsistentMapCommands.TransactionRollback(transactionId)); | ||
281 | + } | ||
282 | + | ||
277 | /** | 283 | /** |
278 | * Change listener context. | 284 | * Change listener context. |
279 | */ | 285 | */ | ... | ... |
... | @@ -28,6 +28,8 @@ import java.util.Map; | ... | @@ -28,6 +28,8 @@ import java.util.Map; |
28 | import java.util.Set; | 28 | import java.util.Set; |
29 | 29 | ||
30 | import org.onlab.util.Match; | 30 | import org.onlab.util.Match; |
31 | +import org.onosproject.store.primitives.TransactionId; | ||
32 | +import org.onosproject.store.primitives.impl.Transaction; | ||
31 | import org.onosproject.store.service.Versioned; | 33 | import org.onosproject.store.service.Versioned; |
32 | 34 | ||
33 | import com.google.common.base.MoreObjects; | 35 | import com.google.common.base.MoreObjects; |
... | @@ -207,35 +209,35 @@ public final class AtomixConsistentMapCommands { | ... | @@ -207,35 +209,35 @@ public final class AtomixConsistentMapCommands { |
207 | */ | 209 | */ |
208 | @SuppressWarnings("serial") | 210 | @SuppressWarnings("serial") |
209 | public static class TransactionPrepare extends MapCommand<PrepareResult> { | 211 | public static class TransactionPrepare extends MapCommand<PrepareResult> { |
210 | - private TransactionalMapUpdate<String, byte[]> update; | 212 | + private Transaction transaction; |
211 | 213 | ||
212 | public TransactionPrepare() { | 214 | public TransactionPrepare() { |
213 | } | 215 | } |
214 | 216 | ||
215 | - public TransactionPrepare(TransactionalMapUpdate<String, byte[]> update) { | 217 | + public TransactionPrepare(Transaction transaction) { |
216 | - this.update = update; | 218 | + this.transaction = transaction; |
217 | } | 219 | } |
218 | 220 | ||
219 | - public TransactionalMapUpdate<String, byte[]> transactionUpdate() { | 221 | + public Transaction transaction() { |
220 | - return update; | 222 | + return transaction; |
221 | } | 223 | } |
222 | 224 | ||
223 | @Override | 225 | @Override |
224 | public void writeObject(BufferOutput<?> buffer, Serializer serializer) { | 226 | public void writeObject(BufferOutput<?> buffer, Serializer serializer) { |
225 | super.writeObject(buffer, serializer); | 227 | super.writeObject(buffer, serializer); |
226 | - serializer.writeObject(update, buffer); | 228 | + serializer.writeObject(transaction, buffer); |
227 | } | 229 | } |
228 | 230 | ||
229 | @Override | 231 | @Override |
230 | public void readObject(BufferInput<?> buffer, Serializer serializer) { | 232 | public void readObject(BufferInput<?> buffer, Serializer serializer) { |
231 | super.readObject(buffer, serializer); | 233 | super.readObject(buffer, serializer); |
232 | - update = serializer.readObject(buffer); | 234 | + transaction = serializer.readObject(buffer); |
233 | } | 235 | } |
234 | 236 | ||
235 | @Override | 237 | @Override |
236 | public String toString() { | 238 | public String toString() { |
237 | return MoreObjects.toStringHelper(getClass()) | 239 | return MoreObjects.toStringHelper(getClass()) |
238 | - .add("update", update) | 240 | + .add("transaction", transaction) |
239 | .toString(); | 241 | .toString(); |
240 | } | 242 | } |
241 | } | 243 | } | ... | ... |
... | @@ -37,6 +37,8 @@ import java.util.stream.Collectors; | ... | @@ -37,6 +37,8 @@ import java.util.stream.Collectors; |
37 | 37 | ||
38 | import org.onlab.util.CountDownCompleter; | 38 | import org.onlab.util.CountDownCompleter; |
39 | import org.onlab.util.Match; | 39 | import org.onlab.util.Match; |
40 | +import org.onosproject.store.primitives.TransactionId; | ||
41 | +import org.onosproject.store.primitives.impl.Transaction; | ||
40 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.TransactionPrepare; | 42 | import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.TransactionPrepare; |
41 | import org.onosproject.store.service.MapEvent; | 43 | import org.onosproject.store.service.MapEvent; |
42 | import org.onosproject.store.service.Versioned; | 44 | import org.onosproject.store.service.Versioned; |
... | @@ -382,9 +384,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -382,9 +384,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
382 | Commit<? extends AtomixConsistentMapCommands.TransactionPrepare> commit) { | 384 | Commit<? extends AtomixConsistentMapCommands.TransactionPrepare> commit) { |
383 | boolean ok = false; | 385 | boolean ok = false; |
384 | try { | 386 | try { |
385 | - TransactionalMapUpdate<String, byte[]> transactionUpdate = commit | 387 | + Transaction transaction = commit.operation().transaction(); |
386 | - .operation().transactionUpdate(); | 388 | + for (MapUpdate<String, byte[]> update : transaction.updates()) { |
387 | - for (MapUpdate<String, byte[]> update : transactionUpdate.batch()) { | ||
388 | String key = update.key(); | 389 | String key = update.key(); |
389 | if (preparedKeys.contains(key)) { | 390 | if (preparedKeys.contains(key)) { |
390 | return PrepareResult.CONCURRENT_TRANSACTION; | 391 | return PrepareResult.CONCURRENT_TRANSACTION; |
... | @@ -403,8 +404,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -403,8 +404,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
403 | // No violations detected. Add to pendingTranctions and mark | 404 | // No violations detected. Add to pendingTranctions and mark |
404 | // modified keys as | 405 | // modified keys as |
405 | // currently locked to updates. | 406 | // currently locked to updates. |
406 | - pendingTransactions.put(transactionUpdate.transactionId(), commit); | 407 | + pendingTransactions.put(transaction.id(), commit); |
407 | - transactionUpdate.batch().forEach(u -> preparedKeys.add(u.key())); | 408 | + transaction.updates().forEach(u -> preparedKeys.add(u.key())); |
408 | ok = true; | 409 | ok = true; |
409 | return PrepareResult.OK; | 410 | return PrepareResult.OK; |
410 | } finally { | 411 | } finally { |
... | @@ -429,16 +430,15 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -429,16 +430,15 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
429 | if (prepareCommit == null) { | 430 | if (prepareCommit == null) { |
430 | return CommitResult.UNKNOWN_TRANSACTION_ID; | 431 | return CommitResult.UNKNOWN_TRANSACTION_ID; |
431 | } | 432 | } |
432 | - TransactionalMapUpdate<String, byte[]> transactionalUpdate = prepareCommit | 433 | + Transaction transaction = prepareCommit.operation().transaction(); |
433 | - .operation().transactionUpdate(); | 434 | + long totalReferencesToCommit = transaction |
434 | - long totalReferencesToCommit = transactionalUpdate | 435 | + .updates() |
435 | - .batch() | ||
436 | .stream() | 436 | .stream() |
437 | .filter(update -> update.type() != MapUpdate.Type.REMOVE_IF_VERSION_MATCH) | 437 | .filter(update -> update.type() != MapUpdate.Type.REMOVE_IF_VERSION_MATCH) |
438 | .count(); | 438 | .count(); |
439 | CountDownCompleter<Commit<? extends AtomixConsistentMapCommands.TransactionPrepare>> completer = | 439 | CountDownCompleter<Commit<? extends AtomixConsistentMapCommands.TransactionPrepare>> completer = |
440 | new CountDownCompleter<>(prepareCommit, totalReferencesToCommit, Commit::close); | 440 | new CountDownCompleter<>(prepareCommit, totalReferencesToCommit, Commit::close); |
441 | - for (MapUpdate<String, byte[]> update : transactionalUpdate.batch()) { | 441 | + for (MapUpdate<String, byte[]> update : transaction.updates()) { |
442 | String key = update.key(); | 442 | String key = update.key(); |
443 | MapEntryValue previousValue = mapEntries.remove(key); | 443 | MapEntryValue previousValue = mapEntries.remove(key); |
444 | MapEntryValue newValue = null; | 444 | MapEntryValue newValue = null; |
... | @@ -473,7 +473,9 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -473,7 +473,9 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
473 | if (prepareCommit == null) { | 473 | if (prepareCommit == null) { |
474 | return RollbackResult.UNKNOWN_TRANSACTION_ID; | 474 | return RollbackResult.UNKNOWN_TRANSACTION_ID; |
475 | } else { | 475 | } else { |
476 | - prepareCommit.operation().transactionUpdate().batch() | 476 | + prepareCommit.operation() |
477 | + .transaction() | ||
478 | + .updates() | ||
477 | .forEach(u -> preparedKeys.remove(u.key())); | 479 | .forEach(u -> preparedKeys.remove(u.key())); |
478 | prepareCommit.close(); | 480 | prepareCommit.close(); |
479 | return RollbackResult.OK; | 481 | return RollbackResult.OK; |
... | @@ -608,9 +610,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -608,9 +610,8 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
608 | 610 | ||
609 | @Override | 611 | @Override |
610 | public byte[] value() { | 612 | public byte[] value() { |
611 | - TransactionalMapUpdate<String, byte[]> update = completer.object() | 613 | + Transaction transaction = completer.object().operation().transaction(); |
612 | - .operation().transactionUpdate(); | 614 | + return valueForKey(key, transaction); |
613 | - return update.valueForKey(key); | ||
614 | } | 615 | } |
615 | 616 | ||
616 | @Override | 617 | @Override |
... | @@ -622,5 +623,14 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements | ... | @@ -622,5 +623,14 @@ public class AtomixConsistentMapState extends ResourceStateMachine implements |
622 | public void discard() { | 623 | public void discard() { |
623 | completer.countDown(); | 624 | completer.countDown(); |
624 | } | 625 | } |
626 | + | ||
627 | + private byte[] valueForKey(String key, Transaction transaction) { | ||
628 | + MapUpdate<String, byte[]> update = transaction.updates() | ||
629 | + .stream() | ||
630 | + .filter(u -> u.key().equals(key)) | ||
631 | + .findFirst() | ||
632 | + .orElse(null); | ||
633 | + return update == null ? null : update.value(); | ||
634 | + } | ||
625 | } | 635 | } |
626 | } | 636 | } | ... | ... |
... | @@ -28,4 +28,14 @@ public enum CommitResult { | ... | @@ -28,4 +28,14 @@ public enum CommitResult { |
28 | * Signifies a failure due to unrecognized transaction identifier. | 28 | * Signifies a failure due to unrecognized transaction identifier. |
29 | */ | 29 | */ |
30 | UNKNOWN_TRANSACTION_ID, | 30 | UNKNOWN_TRANSACTION_ID, |
31 | + | ||
32 | + /** | ||
33 | + * Signifies a failure to get participants to agree to commit (during prepare stage). | ||
34 | + */ | ||
35 | + FAILURE_TO_PREPARE, | ||
36 | + | ||
37 | + /** | ||
38 | + * Failure during commit phase. | ||
39 | + */ | ||
40 | + FAILURE_DURING_COMMIT | ||
31 | } | 41 | } | ... | ... |
... | @@ -29,6 +29,8 @@ import com.google.common.base.MoreObjects; | ... | @@ -29,6 +29,8 @@ import com.google.common.base.MoreObjects; |
29 | * Both old and new values are accessible along with a flag that indicates if the | 29 | * Both old and new values are accessible along with a flag that indicates if the |
30 | * the value was updated. If flag is false, oldValue and newValue both | 30 | * the value was updated. If flag is false, oldValue and newValue both |
31 | * point to the same unmodified value. | 31 | * point to the same unmodified value. |
32 | + * | ||
33 | + * @param <K> key type | ||
32 | * @param <V> result type | 34 | * @param <V> result type |
33 | */ | 35 | */ |
34 | public class MapEntryUpdateResult<K, V> { | 36 | public class MapEntryUpdateResult<K, V> { |
... | @@ -123,6 +125,8 @@ public class MapEntryUpdateResult<K, V> { | ... | @@ -123,6 +125,8 @@ public class MapEntryUpdateResult<K, V> { |
123 | * @param keyTransform transformer to use for transcoding keys | 125 | * @param keyTransform transformer to use for transcoding keys |
124 | * @param valueMapper mapper to use for transcoding values | 126 | * @param valueMapper mapper to use for transcoding values |
125 | * @return new instance | 127 | * @return new instance |
128 | + * @param <K1> key type of returned {@code MapEntryUpdateResult} | ||
129 | + * @param <V1> value type of returned {@code MapEntryUpdateResult} | ||
126 | */ | 130 | */ |
127 | public <K1, V1> MapEntryUpdateResult<K1, V1> map(Function<K, K1> keyTransform, Function<V, V1> valueMapper) { | 131 | public <K1, V1> MapEntryUpdateResult<K1, V1> map(Function<K, K1> keyTransform, Function<V, V1> valueMapper) { |
128 | return new MapEntryUpdateResult<>(status, | 132 | return new MapEntryUpdateResult<>(status, | ... | ... |
... | @@ -70,6 +70,7 @@ public final class MapUpdate<K, V> { | ... | @@ -70,6 +70,7 @@ public final class MapUpdate<K, V> { |
70 | REMOVE_IF_VALUE_MATCH, | 70 | REMOVE_IF_VALUE_MATCH, |
71 | } | 71 | } |
72 | 72 | ||
73 | + private String mapName; | ||
73 | private Type type; | 74 | private Type type; |
74 | private K key; | 75 | private K key; |
75 | private V value; | 76 | private V value; |
... | @@ -77,6 +78,15 @@ public final class MapUpdate<K, V> { | ... | @@ -77,6 +78,15 @@ public final class MapUpdate<K, V> { |
77 | private long currentVersion = -1; | 78 | private long currentVersion = -1; |
78 | 79 | ||
79 | /** | 80 | /** |
81 | + * Returns the name of the map. | ||
82 | + * | ||
83 | + * @return map name | ||
84 | + */ | ||
85 | + public String mapName() { | ||
86 | + return mapName; | ||
87 | + } | ||
88 | + | ||
89 | + /** | ||
80 | * Returns the type of update operation. | 90 | * Returns the type of update operation. |
81 | * @return type of update. | 91 | * @return type of update. |
82 | */ | 92 | */ |
... | @@ -119,6 +129,7 @@ public final class MapUpdate<K, V> { | ... | @@ -119,6 +129,7 @@ public final class MapUpdate<K, V> { |
119 | @Override | 129 | @Override |
120 | public String toString() { | 130 | public String toString() { |
121 | return MoreObjects.toStringHelper(this) | 131 | return MoreObjects.toStringHelper(this) |
132 | + .add("mapName", mapName) | ||
122 | .add("type", type) | 133 | .add("type", type) |
123 | .add("key", key) | 134 | .add("key", key) |
124 | .add("value", value) | 135 | .add("value", value) |
... | @@ -153,6 +164,11 @@ public final class MapUpdate<K, V> { | ... | @@ -153,6 +164,11 @@ public final class MapUpdate<K, V> { |
153 | return update; | 164 | return update; |
154 | } | 165 | } |
155 | 166 | ||
167 | + public Builder<K, V> withMapName(String name) { | ||
168 | + update.mapName = checkNotNull(name, "name cannot be null"); | ||
169 | + return this; | ||
170 | + } | ||
171 | + | ||
156 | public Builder<K, V> withType(Type type) { | 172 | public Builder<K, V> withType(Type type) { |
157 | update.type = checkNotNull(type, "type cannot be null"); | 173 | update.type = checkNotNull(type, "type cannot be null"); |
158 | return this; | 174 | return this; | ... | ... |
... | @@ -25,6 +25,11 @@ public enum PrepareResult { | ... | @@ -25,6 +25,11 @@ public enum PrepareResult { |
25 | OK, | 25 | OK, |
26 | 26 | ||
27 | /** | 27 | /** |
28 | + * Signifies some participants in a distributed prepare operation failed. | ||
29 | + */ | ||
30 | + PARTIAL_FAILURE, | ||
31 | + | ||
32 | + /** | ||
28 | * Signifies a failure to another transaction locking the underlying state. | 33 | * Signifies a failure to another transaction locking the underlying state. |
29 | */ | 34 | */ |
30 | CONCURRENT_TRANSACTION, | 35 | CONCURRENT_TRANSACTION, | ... | ... |
1 | -/* | ||
2 | - * Copyright 2016 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onosproject.store.primitives.resources.impl; | ||
17 | - | ||
18 | -import java.util.Collection; | ||
19 | -import java.util.Map; | ||
20 | - | ||
21 | -import com.google.common.collect.ImmutableList; | ||
22 | -import com.google.common.collect.Maps; | ||
23 | - | ||
24 | -/** | ||
25 | - * A batch updates to an {@code AsyncConsistentMap} be committed as a transaction. | ||
26 | - * | ||
27 | - * @param <K> key type | ||
28 | - * @param <V> value type | ||
29 | - */ | ||
30 | -public class TransactionalMapUpdate<K, V> { | ||
31 | - private final TransactionId transactionId; | ||
32 | - private final Collection<MapUpdate<K, V>> updates; | ||
33 | - private boolean indexPopulated = false; | ||
34 | - private final Map<K, V> keyValueIndex = Maps.newHashMap(); | ||
35 | - | ||
36 | - public TransactionalMapUpdate(TransactionId transactionId, Collection<MapUpdate<K, V>> updates) { | ||
37 | - this.transactionId = transactionId; | ||
38 | - this.updates = ImmutableList.copyOf(updates); | ||
39 | - populateIndex(); | ||
40 | - } | ||
41 | - | ||
42 | - /** | ||
43 | - * Returns the transaction identifier. | ||
44 | - * @return transaction id | ||
45 | - */ | ||
46 | - public TransactionId transactionId() { | ||
47 | - return transactionId; | ||
48 | - } | ||
49 | - | ||
50 | - /** | ||
51 | - * Returns the collection of map updates. | ||
52 | - * @return map updates | ||
53 | - */ | ||
54 | - public Collection<MapUpdate<K, V>> batch() { | ||
55 | - return updates; | ||
56 | - } | ||
57 | - | ||
58 | - /** | ||
59 | - * Returns the value that will be associated with the key after this transaction commits. | ||
60 | - * @param key key | ||
61 | - * @return value that will be associated with the value once this transaction commits | ||
62 | - */ | ||
63 | - public V valueForKey(K key) { | ||
64 | - if (!indexPopulated) { | ||
65 | - // We do not synchronize as we don't expect this called to be made from multiple threads. | ||
66 | - populateIndex(); | ||
67 | - } | ||
68 | - return keyValueIndex.get(key); | ||
69 | - } | ||
70 | - | ||
71 | - /** | ||
72 | - * Populates the internal key -> value mapping. | ||
73 | - */ | ||
74 | - private synchronized void populateIndex() { | ||
75 | - updates.forEach(mapUpdate -> { | ||
76 | - if (mapUpdate.value() != null) { | ||
77 | - keyValueIndex.put(mapUpdate.key(), mapUpdate.value()); | ||
78 | - } | ||
79 | - }); | ||
80 | - indexPopulated = true; | ||
81 | - } | ||
82 | -} |
... | @@ -41,7 +41,6 @@ import org.onlab.util.Match; | ... | @@ -41,7 +41,6 @@ import org.onlab.util.Match; |
41 | import org.onosproject.core.ApplicationId; | 41 | import org.onosproject.core.ApplicationId; |
42 | import org.onosproject.core.DefaultApplicationId; | 42 | import org.onosproject.core.DefaultApplicationId; |
43 | import org.onosproject.store.service.Serializer; | 43 | import org.onosproject.store.service.Serializer; |
44 | -import org.onosproject.store.service.Transaction; | ||
45 | import org.onosproject.store.service.Versioned; | 44 | import org.onosproject.store.service.Versioned; |
46 | 45 | ||
47 | import com.google.common.base.MoreObjects; | 46 | import com.google.common.base.MoreObjects; | ... | ... |
... | @@ -27,6 +27,8 @@ import java.util.stream.Collectors; | ... | @@ -27,6 +27,8 @@ import java.util.stream.Collectors; |
27 | import org.junit.Ignore; | 27 | import org.junit.Ignore; |
28 | import org.junit.Test; | 28 | import org.junit.Test; |
29 | import org.onlab.util.Tools; | 29 | import org.onlab.util.Tools; |
30 | +import org.onosproject.store.primitives.TransactionId; | ||
31 | +import org.onosproject.store.primitives.impl.Transaction; | ||
30 | import org.onosproject.store.service.MapEvent; | 32 | import org.onosproject.store.service.MapEvent; |
31 | import org.onosproject.store.service.MapEventListener; | 33 | import org.onosproject.store.service.MapEventListener; |
32 | import org.onosproject.store.service.Versioned; | 34 | import org.onosproject.store.service.Versioned; |
... | @@ -351,10 +353,9 @@ public class AtomixConsistentMapTest extends AtomixTestBase { | ... | @@ -351,10 +353,9 @@ public class AtomixConsistentMapTest extends AtomixTestBase { |
351 | .withValue(value1) | 353 | .withValue(value1) |
352 | .build(); | 354 | .build(); |
353 | 355 | ||
354 | - TransactionalMapUpdate<String, byte[]> txMapUpdate = | 356 | + Transaction tx = new Transaction(TransactionId.from("tx1"), Arrays.asList(update1)); |
355 | - new TransactionalMapUpdate<>(TransactionId.from("tx1"), Arrays.asList(update1)); | ||
356 | 357 | ||
357 | - map.prepare(txMapUpdate).thenAccept(result -> { | 358 | + map.prepare(tx).thenAccept(result -> { |
358 | assertEquals(PrepareResult.OK, result); | 359 | assertEquals(PrepareResult.OK, result); |
359 | }).join(); | 360 | }).join(); |
360 | assertNull(listener.event()); | 361 | assertNull(listener.event()); |
... | @@ -376,7 +377,7 @@ public class AtomixConsistentMapTest extends AtomixTestBase { | ... | @@ -376,7 +377,7 @@ public class AtomixConsistentMapTest extends AtomixTestBase { |
376 | 377 | ||
377 | assertNull(listener.event()); | 378 | assertNull(listener.event()); |
378 | 379 | ||
379 | - map.commit(txMapUpdate.transactionId()).join(); | 380 | + map.commit(tx.id()).join(); |
380 | assertNotNull(listener.event()); | 381 | assertNotNull(listener.event()); |
381 | assertEquals(MapEvent.Type.INSERT, listener.event().type()); | 382 | assertEquals(MapEvent.Type.INSERT, listener.event().type()); |
382 | assertTrue(Arrays.equals(value1, listener.event().newValue().value())); | 383 | assertTrue(Arrays.equals(value1, listener.event().newValue().value())); |
... | @@ -406,14 +407,13 @@ public class AtomixConsistentMapTest extends AtomixTestBase { | ... | @@ -406,14 +407,13 @@ public class AtomixConsistentMapTest extends AtomixTestBase { |
406 | .withKey("foo") | 407 | .withKey("foo") |
407 | .withValue(value1) | 408 | .withValue(value1) |
408 | .build(); | 409 | .build(); |
409 | - TransactionalMapUpdate<String, byte[]> txMapUpdate = | 410 | + Transaction tx = new Transaction(TransactionId.from("tx1"), Arrays.asList(update1)); |
410 | - new TransactionalMapUpdate<>(TransactionId.from("tx1"), Arrays.asList(update1)); | 411 | + map.prepare(tx).thenAccept(result -> { |
411 | - map.prepare(txMapUpdate).thenAccept(result -> { | ||
412 | assertEquals(PrepareResult.OK, result); | 412 | assertEquals(PrepareResult.OK, result); |
413 | }).join(); | 413 | }).join(); |
414 | assertNull(listener.event()); | 414 | assertNull(listener.event()); |
415 | 415 | ||
416 | - map.rollback(txMapUpdate.transactionId()).join(); | 416 | + map.rollback(tx.id()).join(); |
417 | assertNull(listener.event()); | 417 | assertNull(listener.event()); |
418 | 418 | ||
419 | map.get("foo").thenAccept(result -> { | 419 | map.get("foo").thenAccept(result -> { | ... | ... |
... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onosproject.store.service; | 16 | +package org.onosproject.store.primitives.resources.impl; |
17 | 17 | ||
18 | import com.google.common.testing.EqualsTester; | 18 | import com.google.common.testing.EqualsTester; |
19 | import org.junit.Test; | 19 | import org.junit.Test; |
... | @@ -22,63 +22,63 @@ import static org.hamcrest.MatcherAssert.assertThat; | ... | @@ -22,63 +22,63 @@ import static org.hamcrest.MatcherAssert.assertThat; |
22 | import static org.hamcrest.Matchers.is; | 22 | import static org.hamcrest.Matchers.is; |
23 | 23 | ||
24 | /** | 24 | /** |
25 | - * Unit Tests for DatabseUpdate class. | 25 | + * Unit Tests for MapUpdate class. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | -public class DatabaseUpdateTest { | 28 | +public class MapUpdateTest { |
29 | 29 | ||
30 | - private final DatabaseUpdate stats1 = DatabaseUpdate.newBuilder() | 30 | + private final MapUpdate<String, byte[]> stats1 = MapUpdate.<String, byte[]>newBuilder() |
31 | .withCurrentValue("1".getBytes()) | 31 | .withCurrentValue("1".getBytes()) |
32 | .withValue("2".getBytes()) | 32 | .withValue("2".getBytes()) |
33 | .withCurrentVersion(3) | 33 | .withCurrentVersion(3) |
34 | .withKey("4") | 34 | .withKey("4") |
35 | .withMapName("5") | 35 | .withMapName("5") |
36 | - .withType(DatabaseUpdate.Type.PUT) | 36 | + .withType(MapUpdate.Type.PUT) |
37 | .build(); | 37 | .build(); |
38 | 38 | ||
39 | - private final DatabaseUpdate stats2 = DatabaseUpdate.newBuilder() | 39 | + private final MapUpdate<String, byte[]> stats2 = MapUpdate.<String, byte[]>newBuilder() |
40 | .withCurrentValue("1".getBytes()) | 40 | .withCurrentValue("1".getBytes()) |
41 | .withValue("2".getBytes()) | 41 | .withValue("2".getBytes()) |
42 | .withCurrentVersion(3) | 42 | .withCurrentVersion(3) |
43 | .withKey("4") | 43 | .withKey("4") |
44 | .withMapName("5") | 44 | .withMapName("5") |
45 | - .withType(DatabaseUpdate.Type.REMOVE) | 45 | + .withType(MapUpdate.Type.REMOVE) |
46 | .build(); | 46 | .build(); |
47 | 47 | ||
48 | - private final DatabaseUpdate stats3 = DatabaseUpdate.newBuilder() | 48 | + private final MapUpdate<String, byte[]> stats3 = MapUpdate.<String, byte[]>newBuilder() |
49 | .withCurrentValue("1".getBytes()) | 49 | .withCurrentValue("1".getBytes()) |
50 | .withValue("2".getBytes()) | 50 | .withValue("2".getBytes()) |
51 | .withCurrentVersion(3) | 51 | .withCurrentVersion(3) |
52 | .withKey("4") | 52 | .withKey("4") |
53 | .withMapName("5") | 53 | .withMapName("5") |
54 | - .withType(DatabaseUpdate.Type.REMOVE_IF_VALUE_MATCH) | 54 | + .withType(MapUpdate.Type.REMOVE_IF_VALUE_MATCH) |
55 | .build(); | 55 | .build(); |
56 | 56 | ||
57 | - private final DatabaseUpdate stats4 = DatabaseUpdate.newBuilder() | 57 | + private final MapUpdate<String, byte[]> stats4 = MapUpdate.<String, byte[]>newBuilder() |
58 | .withCurrentValue("1".getBytes()) | 58 | .withCurrentValue("1".getBytes()) |
59 | .withValue("2".getBytes()) | 59 | .withValue("2".getBytes()) |
60 | .withCurrentVersion(3) | 60 | .withCurrentVersion(3) |
61 | .withKey("4") | 61 | .withKey("4") |
62 | .withMapName("5") | 62 | .withMapName("5") |
63 | - .withType(DatabaseUpdate.Type.REMOVE_IF_VERSION_MATCH) | 63 | + .withType(MapUpdate.Type.REMOVE_IF_VERSION_MATCH) |
64 | .build(); | 64 | .build(); |
65 | 65 | ||
66 | - private final DatabaseUpdate stats5 = DatabaseUpdate.newBuilder() | 66 | + private final MapUpdate<String, byte[]> stats5 = MapUpdate.<String, byte[]>newBuilder() |
67 | .withCurrentValue("1".getBytes()) | 67 | .withCurrentValue("1".getBytes()) |
68 | .withValue("2".getBytes()) | 68 | .withValue("2".getBytes()) |
69 | .withCurrentVersion(3) | 69 | .withCurrentVersion(3) |
70 | .withKey("4") | 70 | .withKey("4") |
71 | .withMapName("5") | 71 | .withMapName("5") |
72 | - .withType(DatabaseUpdate.Type.PUT_IF_VALUE_MATCH) | 72 | + .withType(MapUpdate.Type.PUT_IF_VALUE_MATCH) |
73 | .build(); | 73 | .build(); |
74 | 74 | ||
75 | - private final DatabaseUpdate stats6 = DatabaseUpdate.newBuilder() | 75 | + private final MapUpdate<String, byte[]> stats6 = MapUpdate.<String, byte[]>newBuilder() |
76 | .withCurrentValue("1".getBytes()) | 76 | .withCurrentValue("1".getBytes()) |
77 | .withValue("2".getBytes()) | 77 | .withValue("2".getBytes()) |
78 | .withCurrentVersion(3) | 78 | .withCurrentVersion(3) |
79 | .withKey("4") | 79 | .withKey("4") |
80 | .withMapName("5") | 80 | .withMapName("5") |
81 | - .withType(DatabaseUpdate.Type.PUT_IF_VERSION_MATCH) | 81 | + .withType(MapUpdate.Type.PUT_IF_VERSION_MATCH) |
82 | .build(); | 82 | .build(); |
83 | 83 | ||
84 | /** | 84 | /** |
... | @@ -91,7 +91,7 @@ public class DatabaseUpdateTest { | ... | @@ -91,7 +91,7 @@ public class DatabaseUpdateTest { |
91 | assertThat(stats1.currentVersion(), is(3L)); | 91 | assertThat(stats1.currentVersion(), is(3L)); |
92 | assertThat(stats1.key(), is("4")); | 92 | assertThat(stats1.key(), is("4")); |
93 | assertThat(stats1.mapName(), is("5")); | 93 | assertThat(stats1.mapName(), is("5")); |
94 | - assertThat(stats1.type(), is(DatabaseUpdate.Type.PUT)); | 94 | + assertThat(stats1.type(), is(MapUpdate.Type.PUT)); |
95 | } | 95 | } |
96 | 96 | ||
97 | /** | 97 | /** | ... | ... |
... | @@ -199,6 +199,7 @@ import org.onosproject.net.resource.link.MplsLabelResourceAllocation; | ... | @@ -199,6 +199,7 @@ import org.onosproject.net.resource.link.MplsLabelResourceAllocation; |
199 | import org.onosproject.net.resource.link.MplsLabelResourceRequest; | 199 | import org.onosproject.net.resource.link.MplsLabelResourceRequest; |
200 | import org.onosproject.security.Permission; | 200 | import org.onosproject.security.Permission; |
201 | import org.onosproject.store.Timestamp; | 201 | import org.onosproject.store.Timestamp; |
202 | +import org.onosproject.store.primitives.TransactionId; | ||
202 | import org.onosproject.store.service.MapEvent; | 203 | import org.onosproject.store.service.MapEvent; |
203 | import org.onosproject.store.service.SetEvent; | 204 | import org.onosproject.store.service.SetEvent; |
204 | import org.onosproject.store.service.Versioned; | 205 | import org.onosproject.store.service.Versioned; |
... | @@ -483,6 +484,7 @@ public final class KryoNamespaces { | ... | @@ -483,6 +484,7 @@ public final class KryoNamespaces { |
483 | .register(new ExtensionCriterionSerializer(), ExtensionCriterion.class) | 484 | .register(new ExtensionCriterionSerializer(), ExtensionCriterion.class) |
484 | .register(ExtensionSelectorType.class) | 485 | .register(ExtensionSelectorType.class) |
485 | .register(ExtensionTreatmentType.class) | 486 | .register(ExtensionTreatmentType.class) |
487 | + .register(TransactionId.class) | ||
486 | .register(Versioned.class) | 488 | .register(Versioned.class) |
487 | .register(MapEvent.class) | 489 | .register(MapEvent.class) |
488 | .register(MapEvent.Type.class) | 490 | .register(MapEvent.Type.class) | ... | ... |
-
Please register or login to post a comment