Using net.jodah.expiringmap.ExpiringMap for tracking ttl expiration of database entries.
Minor javadoc updates.
Showing
7 changed files
with
128 additions
and
103 deletions
... | @@ -22,6 +22,7 @@ public class ReadResult { | ... | @@ -22,6 +22,7 @@ public class ReadResult { |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * Returns the status of the read operation. | 24 | * Returns the status of the read operation. |
25 | + * @return read operation status | ||
25 | */ | 26 | */ |
26 | public ReadStatus status() { | 27 | public ReadStatus status() { |
27 | return status; | 28 | return status; | ... | ... |
... | @@ -20,11 +20,12 @@ import java.io.IOException; | ... | @@ -20,11 +20,12 @@ import java.io.IOException; |
20 | import java.util.HashMap; | 20 | import java.util.HashMap; |
21 | import java.util.Map; | 21 | import java.util.Map; |
22 | import java.util.Objects; | 22 | import java.util.Objects; |
23 | +import java.util.concurrent.TimeUnit; | ||
23 | import java.util.concurrent.atomic.AtomicBoolean; | 24 | import java.util.concurrent.atomic.AtomicBoolean; |
24 | 25 | ||
25 | -//import net.jodah.expiringmap.ExpiringMap; | 26 | +import net.jodah.expiringmap.ExpiringMap; |
26 | -//import net.jodah.expiringmap.ExpiringMap.ExpirationListener; | 27 | +import net.jodah.expiringmap.ExpiringMap.ExpirationListener; |
27 | -//import net.jodah.expiringmap.ExpiringMap.ExpirationPolicy; | 28 | +import net.jodah.expiringmap.ExpiringMap.ExpirationPolicy; |
28 | import net.kuujo.copycat.cluster.Member; | 29 | import net.kuujo.copycat.cluster.Member; |
29 | import net.kuujo.copycat.event.EventHandler; | 30 | import net.kuujo.copycat.event.EventHandler; |
30 | import net.kuujo.copycat.event.LeaderElectEvent; | 31 | import net.kuujo.copycat.event.LeaderElectEvent; |
... | @@ -34,19 +35,22 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; | ... | @@ -34,19 +35,22 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; |
34 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; | 35 | import org.onlab.onos.store.cluster.messaging.ClusterMessage; |
35 | import org.onlab.onos.store.cluster.messaging.MessageSubject; | 36 | import org.onlab.onos.store.cluster.messaging.MessageSubject; |
36 | import org.onlab.onos.store.service.DatabaseService; | 37 | import org.onlab.onos.store.service.DatabaseService; |
38 | +import org.onlab.onos.store.service.VersionedValue; | ||
37 | import org.slf4j.Logger; | 39 | import org.slf4j.Logger; |
38 | import org.slf4j.LoggerFactory; | 40 | import org.slf4j.LoggerFactory; |
39 | 41 | ||
40 | /** | 42 | /** |
41 | - * Database update event handler. | 43 | + * Plugs into the database update stream and track the TTL of entries added to |
44 | + * the database. For tables with pre-configured finite TTL, this class has | ||
45 | + * mechanisms for expiring (deleting) old, expired entries from the database. | ||
42 | */ | 46 | */ |
43 | -public class DatabaseUpdateEventHandler implements | 47 | +public class DatabaseEntryExpirationTracker implements |
44 | - DatabaseUpdateEventListener, EventHandler<LeaderElectEvent> { | 48 | + DatabaseUpdateEventListener, EventHandler<LeaderElectEvent> { |
45 | 49 | ||
46 | private final Logger log = LoggerFactory.getLogger(getClass()); | 50 | private final Logger log = LoggerFactory.getLogger(getClass()); |
47 | 51 | ||
48 | - public static final MessageSubject DATABASE_UPDATES = | 52 | + public static final MessageSubject DATABASE_UPDATES = new MessageSubject( |
49 | - new MessageSubject("database-update-event"); | 53 | + "database-update-event"); |
50 | 54 | ||
51 | private DatabaseService databaseService; | 55 | private DatabaseService databaseService; |
52 | private ClusterService cluster; | 56 | private ClusterService cluster; |
... | @@ -54,29 +58,32 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -54,29 +58,32 @@ public class DatabaseUpdateEventHandler implements |
54 | 58 | ||
55 | private final Member localMember; | 59 | private final Member localMember; |
56 | private final AtomicBoolean isLocalMemberLeader = new AtomicBoolean(false); | 60 | private final AtomicBoolean isLocalMemberLeader = new AtomicBoolean(false); |
57 | - private final Map<String, Map<DatabaseRow, Void>> tableEntryExpirationMap = new HashMap<>(); | ||
58 | - //private final ExpirationListener<DatabaseRow, Void> expirationObserver = new ExpirationObserver(); | ||
59 | 61 | ||
60 | - DatabaseUpdateEventHandler(Member localMember) { | 62 | + private final Map<String, Map<DatabaseRow, VersionedValue>> tableEntryExpirationMap = new HashMap<>(); |
63 | + | ||
64 | + private final ExpirationListener<DatabaseRow, VersionedValue> expirationObserver = new ExpirationObserver(); | ||
65 | + | ||
66 | + DatabaseEntryExpirationTracker(Member localMember) { | ||
61 | this.localMember = localMember; | 67 | this.localMember = localMember; |
62 | } | 68 | } |
63 | 69 | ||
64 | @Override | 70 | @Override |
65 | public void tableModified(TableModificationEvent event) { | 71 | public void tableModified(TableModificationEvent event) { |
66 | DatabaseRow row = new DatabaseRow(event.tableName(), event.key()); | 72 | DatabaseRow row = new DatabaseRow(event.tableName(), event.key()); |
67 | - Map<DatabaseRow, Void> map = tableEntryExpirationMap.get(event.tableName()); | 73 | + Map<DatabaseRow, VersionedValue> map = tableEntryExpirationMap |
74 | + .get(event.tableName()); | ||
68 | 75 | ||
69 | switch (event.type()) { | 76 | switch (event.type()) { |
70 | case ROW_DELETED: | 77 | case ROW_DELETED: |
71 | if (isLocalMemberLeader.get()) { | 78 | if (isLocalMemberLeader.get()) { |
72 | try { | 79 | try { |
73 | - clusterCommunicator.broadcast( | 80 | + clusterCommunicator.broadcast(new ClusterMessage(cluster |
74 | - new ClusterMessage( | 81 | + .getLocalNode().id(), DATABASE_UPDATES, |
75 | - cluster.getLocalNode().id(), | 82 | + DatabaseStateMachine.SERIALIZER.encode(event))); |
76 | - DATABASE_UPDATES, | ||
77 | - DatabaseStateMachine.SERIALIZER.encode(event))); | ||
78 | } catch (IOException e) { | 83 | } catch (IOException e) { |
79 | - log.error("Failed to broadcast a database table modification event.", e); | 84 | + log.error( |
85 | + "Failed to broadcast a database table modification event.", | ||
86 | + e); | ||
80 | } | 87 | } |
81 | } | 88 | } |
82 | break; | 89 | break; |
... | @@ -94,15 +101,11 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -94,15 +101,11 @@ public class DatabaseUpdateEventHandler implements |
94 | // make this explicit instead of relying on a negative value | 101 | // make this explicit instead of relying on a negative value |
95 | // to indicate no expiration. | 102 | // to indicate no expiration. |
96 | if (expirationTimeMillis > 0) { | 103 | if (expirationTimeMillis > 0) { |
97 | - tableEntryExpirationMap.put(tableName, null); | 104 | + tableEntryExpirationMap.put(tableName, ExpiringMap.builder() |
98 | - /* | ||
99 | - ExpiringMap.builder() | ||
100 | .expiration(expirationTimeMillis, TimeUnit.SECONDS) | 105 | .expiration(expirationTimeMillis, TimeUnit.SECONDS) |
101 | .expirationListener(expirationObserver) | 106 | .expirationListener(expirationObserver) |
102 | // FIXME: make the expiration policy configurable. | 107 | // FIXME: make the expiration policy configurable. |
103 | - .expirationPolicy(ExpirationPolicy.CREATED) | 108 | + .expirationPolicy(ExpirationPolicy.CREATED).build()); |
104 | - .build()); | ||
105 | - */ | ||
106 | } | 109 | } |
107 | } | 110 | } |
108 | 111 | ||
... | @@ -111,27 +114,40 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -111,27 +114,40 @@ public class DatabaseUpdateEventHandler implements |
111 | tableEntryExpirationMap.remove(tableName); | 114 | tableEntryExpirationMap.remove(tableName); |
112 | } | 115 | } |
113 | 116 | ||
114 | - /* | 117 | + private class ExpirationObserver implements |
115 | - private class ExpirationObserver implements ExpirationListener<DatabaseRow, Void> { | 118 | + ExpirationListener<DatabaseRow, VersionedValue> { |
116 | @Override | 119 | @Override |
117 | - public void expired(DatabaseRow key, Void value) { | 120 | + public void expired(DatabaseRow key, VersionedValue value) { |
118 | try { | 121 | try { |
119 | - // TODO: The safety of this check needs to be verified. | ||
120 | - // Couple of issues: | ||
121 | - // 1. It is very likely that only one member should attempt deletion of the entry from database. | ||
122 | - // 2. A potential race condition exists where the entry expires, but before its can be deleted | ||
123 | - // from the database, a new entry is added or existing entry is updated. | ||
124 | - // That means ttl and expiration should be for a given version. | ||
125 | if (isLocalMemberLeader.get()) { | 122 | if (isLocalMemberLeader.get()) { |
126 | - databaseService.remove(key.tableName, key.key); | 123 | + if (!databaseService.removeIfVersionMatches(key.tableName, |
124 | + key.key, value.version())) { | ||
125 | + log.info("Entry in the database changed before right its TTL expiration."); | ||
126 | + } | ||
127 | + } else { | ||
128 | + // If this node is not the current leader, we should never | ||
129 | + // let the expiring entries drop off | ||
130 | + // Under stable conditions (i.e no leadership switch) the | ||
131 | + // current leader will initiate | ||
132 | + // a database remove and this instance will get notified | ||
133 | + // of a tableModification event causing it to remove from | ||
134 | + // the map. | ||
135 | + Map<DatabaseRow, VersionedValue> map = tableEntryExpirationMap | ||
136 | + .get(key.tableName); | ||
137 | + if (map != null) { | ||
138 | + map.put(key, value); | ||
139 | + } | ||
127 | } | 140 | } |
141 | + | ||
128 | } catch (Exception e) { | 142 | } catch (Exception e) { |
129 | - log.warn("Failed to delete entry from the database after ttl expiration. Will retry eviction", e); | 143 | + log.warn( |
130 | - tableEntryExpirationMap.get(key.tableName).put(new DatabaseRow(key.tableName, key.key), null); | 144 | + "Failed to delete entry from the database after ttl expiration. Will retry eviction", |
145 | + e); | ||
146 | + tableEntryExpirationMap.get(key.tableName).put( | ||
147 | + new DatabaseRow(key.tableName, key.key), value); | ||
131 | } | 148 | } |
132 | } | 149 | } |
133 | } | 150 | } |
134 | - */ | ||
135 | 151 | ||
136 | @Override | 152 | @Override |
137 | public void handle(LeaderElectEvent event) { | 153 | public void handle(LeaderElectEvent event) { |
... | @@ -140,6 +156,9 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -140,6 +156,9 @@ public class DatabaseUpdateEventHandler implements |
140 | } | 156 | } |
141 | } | 157 | } |
142 | 158 | ||
159 | + /** | ||
160 | + * Wrapper class for a database row identifier. | ||
161 | + */ | ||
143 | private class DatabaseRow { | 162 | private class DatabaseRow { |
144 | 163 | ||
145 | String tableName; | 164 | String tableName; |
... | @@ -160,8 +179,8 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -160,8 +179,8 @@ public class DatabaseUpdateEventHandler implements |
160 | } | 179 | } |
161 | DatabaseRow that = (DatabaseRow) obj; | 180 | DatabaseRow that = (DatabaseRow) obj; |
162 | 181 | ||
163 | - return Objects.equals(this.tableName, that.tableName) && | 182 | + return Objects.equals(this.tableName, that.tableName) |
164 | - Objects.equals(this.key, that.key); | 183 | + && Objects.equals(this.key, that.key); |
165 | } | 184 | } |
166 | 185 | ||
167 | @Override | 186 | @Override |
... | @@ -169,4 +188,4 @@ public class DatabaseUpdateEventHandler implements | ... | @@ -169,4 +188,4 @@ public class DatabaseUpdateEventHandler implements |
169 | return Objects.hash(tableName, key); | 188 | return Objects.hash(tableName, key); |
170 | } | 189 | } |
171 | } | 190 | } |
172 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
191 | +} | ... | ... |
... | @@ -237,8 +237,8 @@ public class DatabaseStateMachine implements StateMachine { | ... | @@ -237,8 +237,8 @@ public class DatabaseStateMachine implements StateMachine { |
237 | WriteResult putResult = new WriteResult(WriteStatus.OK, previousValue); | 237 | WriteResult putResult = new WriteResult(WriteStatus.OK, previousValue); |
238 | results.add(putResult); | 238 | results.add(putResult); |
239 | tableModificationEvent = (previousValue == null) ? | 239 | tableModificationEvent = (previousValue == null) ? |
240 | - TableModificationEvent.rowAdded(request.tableName(), request.key()) : | 240 | + TableModificationEvent.rowAdded(request.tableName(), request.key(), newValue) : |
241 | - TableModificationEvent.rowUpdated(request.tableName(), request.key()); | 241 | + TableModificationEvent.rowUpdated(request.tableName(), request.key(), newValue); |
242 | break; | 242 | break; |
243 | 243 | ||
244 | case REMOVE: | 244 | case REMOVE: |
... | @@ -249,7 +249,7 @@ public class DatabaseStateMachine implements StateMachine { | ... | @@ -249,7 +249,7 @@ public class DatabaseStateMachine implements StateMachine { |
249 | results.add(removeResult); | 249 | results.add(removeResult); |
250 | if (removedValue != null) { | 250 | if (removedValue != null) { |
251 | tableModificationEvent = | 251 | tableModificationEvent = |
252 | - TableModificationEvent.rowDeleted(request.tableName(), request.key()); | 252 | + TableModificationEvent.rowDeleted(request.tableName(), request.key(), removedValue); |
253 | } | 253 | } |
254 | break; | 254 | break; |
255 | 255 | ... | ... |
... | @@ -29,15 +29,14 @@ public interface DatabaseUpdateEventListener { | ... | @@ -29,15 +29,14 @@ public interface DatabaseUpdateEventListener { |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * Notifies listeners of a table created event. | 31 | * Notifies listeners of a table created event. |
32 | - * @param tableName | 32 | + * @param tableName name of the table created |
33 | - * @param expirationTimeMillis | 33 | + * @param expirationTimeMillis TTL for entries added to the table (measured since last update time) |
34 | */ | 34 | */ |
35 | public void tableCreated(String tableName, int expirationTimeMillis); | 35 | public void tableCreated(String tableName, int expirationTimeMillis); |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * Notifies listeners of a table deleted event. | 38 | * Notifies listeners of a table deleted event. |
39 | - * @param tableName | 39 | + * @param tableName name of the table deleted |
40 | */ | 40 | */ |
41 | public void tableDeleted(String tableName); | 41 | public void tableDeleted(String tableName); |
42 | - | ||
43 | } | 42 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -33,7 +33,8 @@ public class DistributedLockManager implements LockService { | ... | @@ -33,7 +33,8 @@ public class DistributedLockManager implements LockService { |
33 | 33 | ||
34 | public static final String ONOS_LOCK_TABLE_NAME = "onos-locks"; | 34 | public static final String ONOS_LOCK_TABLE_NAME = "onos-locks"; |
35 | 35 | ||
36 | - private final ArrayListMultimap<String, LockRequest> locksToAcquire = ArrayListMultimap.create(); | 36 | + private final ArrayListMultimap<String, LockRequest> locksToAcquire = ArrayListMultimap |
37 | + .create(); | ||
37 | 38 | ||
38 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 39 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
39 | private ClusterCommunicationService clusterCommunicator; | 40 | private ClusterCommunicationService clusterCommunicator; |
... | @@ -61,11 +62,7 @@ public class DistributedLockManager implements LockService { | ... | @@ -61,11 +62,7 @@ public class DistributedLockManager implements LockService { |
61 | 62 | ||
62 | @Override | 63 | @Override |
63 | public Lock create(String path) { | 64 | public Lock create(String path) { |
64 | - return new DistributedLock( | 65 | + return new DistributedLock(path, databaseService, clusterService, this); |
65 | - path, | ||
66 | - databaseService, | ||
67 | - clusterService, | ||
68 | - this); | ||
69 | } | 66 | } |
70 | 67 | ||
71 | @Override | 68 | @Override |
... | @@ -80,21 +77,19 @@ public class DistributedLockManager implements LockService { | ... | @@ -80,21 +77,19 @@ public class DistributedLockManager implements LockService { |
80 | throw new UnsupportedOperationException(); | 77 | throw new UnsupportedOperationException(); |
81 | } | 78 | } |
82 | 79 | ||
83 | - protected CompletableFuture<Void> lockIfAvailable( | 80 | + protected CompletableFuture<Void> lockIfAvailable(Lock lock, |
84 | - Lock lock, | 81 | + long waitTimeMillis, int leaseDurationMillis) { |
85 | - long waitTimeMillis, | ||
86 | - int leaseDurationMillis) { | ||
87 | CompletableFuture<Void> future = new CompletableFuture<>(); | 82 | CompletableFuture<Void> future = new CompletableFuture<>(); |
88 | - locksToAcquire.put( | 83 | + locksToAcquire.put(lock.path(), new LockRequest(lock, waitTimeMillis, |
89 | - lock.path(), | 84 | + leaseDurationMillis, future)); |
90 | - new LockRequest(lock, waitTimeMillis, leaseDurationMillis, future)); | ||
91 | return future; | 85 | return future; |
92 | } | 86 | } |
93 | 87 | ||
94 | private class LockEventMessageListener implements ClusterMessageHandler { | 88 | private class LockEventMessageListener implements ClusterMessageHandler { |
95 | @Override | 89 | @Override |
96 | public void handle(ClusterMessage message) { | 90 | public void handle(ClusterMessage message) { |
97 | - TableModificationEvent event = DatabaseStateMachine.SERIALIZER.decode(message.payload()); | 91 | + TableModificationEvent event = DatabaseStateMachine.SERIALIZER |
92 | + .decode(message.payload()); | ||
98 | if (!event.tableName().equals(ONOS_LOCK_TABLE_NAME)) { | 93 | if (!event.tableName().equals(ONOS_LOCK_TABLE_NAME)) { |
99 | return; | 94 | return; |
100 | } | 95 | } |
... | @@ -110,15 +105,20 @@ public class DistributedLockManager implements LockService { | ... | @@ -110,15 +105,20 @@ public class DistributedLockManager implements LockService { |
110 | return; | 105 | return; |
111 | } | 106 | } |
112 | 107 | ||
113 | - Iterator<LockRequest> existingRequestIterator = existingRequests.iterator(); | 108 | + synchronized (existingRequests) { |
114 | - while (existingRequestIterator.hasNext()) { | 109 | + |
115 | - LockRequest request = existingRequestIterator.next(); | 110 | + Iterator<LockRequest> existingRequestIterator = existingRequests |
116 | - if (request.expirationTime().isAfter(DateTime.now())) { | 111 | + .iterator(); |
117 | - existingRequestIterator.remove(); | 112 | + while (existingRequestIterator.hasNext()) { |
118 | - } else { | 113 | + LockRequest request = existingRequestIterator.next(); |
119 | - if (request.lock().tryLock(request.leaseDurationMillis())) { | 114 | + if (request.expirationTime().isAfter(DateTime.now())) { |
120 | - request.future().complete(null); | 115 | + existingRequestIterator.remove(); |
121 | - existingRequests.remove(0); | 116 | + } else { |
117 | + if (request.lock().tryLock( | ||
118 | + request.leaseDurationMillis())) { | ||
119 | + request.future().complete(null); | ||
120 | + existingRequestIterator.remove(); | ||
121 | + } | ||
122 | } | 122 | } |
123 | } | 123 | } |
124 | } | 124 | } |
... | @@ -133,14 +133,12 @@ public class DistributedLockManager implements LockService { | ... | @@ -133,14 +133,12 @@ public class DistributedLockManager implements LockService { |
133 | private final int leaseDurationMillis; | 133 | private final int leaseDurationMillis; |
134 | private final CompletableFuture<Void> future; | 134 | private final CompletableFuture<Void> future; |
135 | 135 | ||
136 | - public LockRequest( | 136 | + public LockRequest(Lock lock, long waitTimeMillis, |
137 | - Lock lock, | 137 | + int leaseDurationMillis, CompletableFuture<Void> future) { |
138 | - long waitTimeMillis, | ||
139 | - int leaseDurationMillis, | ||
140 | - CompletableFuture<Void> future) { | ||
141 | 138 | ||
142 | this.lock = lock; | 139 | this.lock = lock; |
143 | - this.expirationTime = DateTime.now().plusMillis((int) waitTimeMillis); | 140 | + this.expirationTime = DateTime.now().plusMillis( |
141 | + (int) waitTimeMillis); | ||
144 | this.leaseDurationMillis = leaseDurationMillis; | 142 | this.leaseDurationMillis = leaseDurationMillis; |
145 | this.future = future; | 143 | this.future = future; |
146 | } | 144 | } | ... | ... |
1 | package org.onlab.onos.store.service.impl; | 1 | package org.onlab.onos.store.service.impl; |
2 | 2 | ||
3 | +import org.onlab.onos.store.service.VersionedValue; | ||
4 | + | ||
3 | /** | 5 | /** |
4 | * A table modification event. | 6 | * A table modification event. |
5 | */ | 7 | */ |
... | @@ -17,41 +19,46 @@ public final class TableModificationEvent { | ... | @@ -17,41 +19,46 @@ public final class TableModificationEvent { |
17 | 19 | ||
18 | private final String tableName; | 20 | private final String tableName; |
19 | private final String key; | 21 | private final String key; |
22 | + private final VersionedValue value; | ||
20 | private final Type type; | 23 | private final Type type; |
21 | 24 | ||
22 | /** | 25 | /** |
23 | * Creates a new row deleted table modification event. | 26 | * Creates a new row deleted table modification event. |
24 | * @param tableName table name. | 27 | * @param tableName table name. |
25 | * @param key row key | 28 | * @param key row key |
29 | + * @param value value associated with the key when it was deleted. | ||
26 | * @return table modification event. | 30 | * @return table modification event. |
27 | */ | 31 | */ |
28 | - public static TableModificationEvent rowDeleted(String tableName, String key) { | 32 | + public static TableModificationEvent rowDeleted(String tableName, String key, VersionedValue value) { |
29 | - return new TableModificationEvent(tableName, key, Type.ROW_DELETED); | 33 | + return new TableModificationEvent(tableName, key, value, Type.ROW_DELETED); |
30 | } | 34 | } |
31 | 35 | ||
32 | /** | 36 | /** |
33 | * Creates a new row added table modification event. | 37 | * Creates a new row added table modification event. |
34 | * @param tableName table name. | 38 | * @param tableName table name. |
35 | * @param key row key | 39 | * @param key row key |
40 | + * @param value value associated with the key | ||
36 | * @return table modification event. | 41 | * @return table modification event. |
37 | */ | 42 | */ |
38 | - public static TableModificationEvent rowAdded(String tableName, String key) { | 43 | + public static TableModificationEvent rowAdded(String tableName, String key, VersionedValue value) { |
39 | - return new TableModificationEvent(tableName, key, Type.ROW_ADDED); | 44 | + return new TableModificationEvent(tableName, key, value, Type.ROW_ADDED); |
40 | } | 45 | } |
41 | 46 | ||
42 | /** | 47 | /** |
43 | * Creates a new row updated table modification event. | 48 | * Creates a new row updated table modification event. |
44 | * @param tableName table name. | 49 | * @param tableName table name. |
45 | * @param key row key | 50 | * @param key row key |
51 | + * @param newValue value | ||
46 | * @return table modification event. | 52 | * @return table modification event. |
47 | */ | 53 | */ |
48 | - public static TableModificationEvent rowUpdated(String tableName, String key) { | 54 | + public static TableModificationEvent rowUpdated(String tableName, String key, VersionedValue newValue) { |
49 | - return new TableModificationEvent(tableName, key, Type.ROW_UPDATED); | 55 | + return new TableModificationEvent(tableName, key, newValue, Type.ROW_UPDATED); |
50 | } | 56 | } |
51 | 57 | ||
52 | - private TableModificationEvent(String tableName, String key, Type type) { | 58 | + private TableModificationEvent(String tableName, String key, VersionedValue value, Type type) { |
53 | this.tableName = tableName; | 59 | this.tableName = tableName; |
54 | this.key = key; | 60 | this.key = key; |
61 | + this.value = value; | ||
55 | this.type = type; | 62 | this.type = type; |
56 | } | 63 | } |
57 | 64 | ||
... | @@ -72,6 +79,15 @@ public final class TableModificationEvent { | ... | @@ -72,6 +79,15 @@ public final class TableModificationEvent { |
72 | } | 79 | } |
73 | 80 | ||
74 | /** | 81 | /** |
82 | + * Returns the value associated with the key. If the event for a deletion, this | ||
83 | + * method returns value that was deleted. | ||
84 | + * @return row value | ||
85 | + */ | ||
86 | + public VersionedValue value() { | ||
87 | + return value; | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
75 | * Returns the type of table modification event. | 91 | * Returns the type of table modification event. |
76 | * @return event type. | 92 | * @return event type. |
77 | */ | 93 | */ | ... | ... |
... | @@ -39,30 +39,23 @@ | ... | @@ -39,30 +39,23 @@ |
39 | </dependency> | 39 | </dependency> |
40 | 40 | ||
41 | <dependency> | 41 | <dependency> |
42 | - <groupId>net.kuujo.copycat</groupId> | 42 | + <groupId>net.jodah</groupId> |
43 | - <artifactId>copycat</artifactId> | 43 | + <artifactId>expiringmap</artifactId> |
44 | - <version>${copycat.version}</version> | 44 | + <version>0.3.1</version> |
45 | </dependency> | 45 | </dependency> |
46 | -<!-- Commented out due to Chronicle + OSGi issue | 46 | + |
47 | <dependency> | 47 | <dependency> |
48 | <groupId>net.kuujo.copycat</groupId> | 48 | <groupId>net.kuujo.copycat</groupId> |
49 | - <artifactId>copycat-chronicle</artifactId> | 49 | + <artifactId>copycat</artifactId> |
50 | <version>${copycat.version}</version> | 50 | <version>${copycat.version}</version> |
51 | </dependency> | 51 | </dependency> |
52 | ---> | 52 | + |
53 | <dependency> | 53 | <dependency> |
54 | <groupId>net.kuujo.copycat</groupId> | 54 | <groupId>net.kuujo.copycat</groupId> |
55 | <artifactId>copycat-tcp</artifactId> | 55 | <artifactId>copycat-tcp</artifactId> |
56 | <version>${copycat.version}</version> | 56 | <version>${copycat.version}</version> |
57 | </dependency> | 57 | </dependency> |
58 | 58 | ||
59 | -<!-- chronicle transitive dependency | ||
60 | - <dependency> | ||
61 | - <groupId>net.java.dev.jna</groupId> | ||
62 | - <artifactId>jna</artifactId> | ||
63 | - <version>4.1.0</version> | ||
64 | - </dependency> | ||
65 | ---> | ||
66 | </dependencies> | 59 | </dependencies> |
67 | 60 | ||
68 | <build> | 61 | <build> |
... | @@ -89,20 +82,19 @@ | ... | @@ -89,20 +82,19 @@ |
89 | </filter> | 82 | </filter> |
90 | 83 | ||
91 | <filter> | 84 | <filter> |
92 | - <artifact>net.kuujo.copycat:*</artifact> | 85 | + <artifact>net.jodah.expiringmap:*</artifact> |
93 | <includes> | 86 | <includes> |
94 | - <include>net/kuujo/copycat/**</include> | 87 | + <include>net/jodah/expiringmap/**</include> |
95 | </includes> | 88 | </includes> |
96 | </filter> | 89 | </filter> |
97 | -<!-- chronicle transitive dependency | ||
98 | 90 | ||
99 | <filter> | 91 | <filter> |
100 | - <artifact>net.java.dev.jna:*</artifact> | 92 | + <artifact>net.kuujo.copycat:*</artifact> |
101 | <includes> | 93 | <includes> |
102 | - <include>com/sun/jna/**</include> | 94 | + <include>net/kuujo/copycat/**</include> |
103 | </includes> | 95 | </includes> |
104 | </filter> | 96 | </filter> |
105 | ---> | 97 | + |
106 | </filters> | 98 | </filters> |
107 | </configuration> | 99 | </configuration> |
108 | <executions> | 100 | <executions> |
... | @@ -120,7 +112,7 @@ | ... | @@ -120,7 +112,7 @@ |
120 | <configuration> | 112 | <configuration> |
121 | <instructions> | 113 | <instructions> |
122 | <Export-Package> | 114 | <Export-Package> |
123 | - com.googlecode.concurrenttrees.*;net.kuujo.copycat.* | 115 | + com.googlecode.concurrenttrees.*;net.kuujo.copycat.*;net.jodah.expiringmap.* |
124 | </Export-Package> | 116 | </Export-Package> |
125 | </instructions> | 117 | </instructions> |
126 | </configuration> | 118 | </configuration> | ... | ... |
-
Please register or login to post a comment