Skip to content

Commit f7b8471

Browse files
author
Keith R. Gustafson
committed
Optionally skip updating methodValueCache/listeners when nothing updated
When useAffectedRows is available, use that to determine whether put() actually affected rows in the database. If not, don't bother updating the methodValueCache or notifying the listeners. This is most valuable as a way to avoid sending pointless JMS messages via CacheMessageManager.
1 parent 3e21ae6 commit f7b8471

File tree

5 files changed

+146
-67
lines changed

5 files changed

+146
-67
lines changed

Diff for: gemini/src/main/java/com/techempower/cache/CacheGroup.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public TLongObjectMap<T> map()
241241
* Add an object to the cache and the data store.
242242
*/
243243
@Override
244-
public void put(T object)
244+
public int put(T object)
245245
{
246246
if (readOnly())
247247
{
@@ -255,7 +255,7 @@ public void put(T object)
255255
final boolean persisted = isPersisted(object);
256256

257257
// Persist the object.
258-
putPersistent(object);
258+
int rowsUpdated = putPersistent(object);
259259

260260
if (persisted)
261261
{
@@ -268,6 +268,7 @@ public void put(T object)
268268
// Object was not persisted, so let's add it to the cache.
269269
addToCache(object);
270270
}
271+
return rowsUpdated;
271272
}
272273

273274
/**
@@ -278,18 +279,18 @@ public void put(T object)
278279
* This method is exposed as a protected class to allow subclasses to
279280
* specialize the persistence behavior.
280281
*/
281-
protected void putPersistent(T object)
282+
protected int putPersistent(T object)
282283
{
283284
// Ask the EntityGroup parent to persist the changes.
284-
super.put(object);
285+
return super.put(object);
285286
}
286287

287288
/**
288289
* Add objects to the cache and the data store.
289290
*/
290291
@SuppressWarnings("unchecked")
291292
@Override
292-
public void putAll(Collection<T> objectsToPut)
293+
public int putAll(Collection<T> objectsToPut)
293294
{
294295
if (readOnly())
295296
{
@@ -315,14 +316,16 @@ public void putAll(Collection<T> objectsToPut)
315316
}
316317

317318
// Persist the changes.
318-
putAllPersistent(objectsToPut);
319+
int rowsUpdated = putAllPersistent(objectsToPut);
319320

320321
// Reorder any previously-persisted objects in case the field we are
321322
// ordered by was changed.
322323
reorder(CollectionHelper.toLongArray(persisted));
323324

324325
// Add any objects we did not previously know about.
325326
addToCache(nonPersisted.toArray((T[])Array.newInstance(type(), nonPersisted.size())));
327+
328+
return rowsUpdated;
326329
}
327330

328331
/**
@@ -333,10 +336,10 @@ public void putAll(Collection<T> objectsToPut)
333336
* This method is exposed as a protected class to allow subclasses to
334337
* specialize the persistence behavior.
335338
*/
336-
protected void putAllPersistent(Collection<T> objectsToPut)
339+
protected int putAllPersistent(Collection<T> objectsToPut)
337340
{
338341
// Ask the EntityGroup parent to persist the objects.
339-
super.putAll(objectsToPut);
342+
return super.putAll(objectsToPut);
340343
}
341344

342345
/**

Diff for: gemini/src/main/java/com/techempower/cache/EntityStore.java

+57-30
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ public class EntityStore
104104
private boolean initialized = false;
105105
private boolean cacheMethodValues = false;
106106

107+
/**
108+
* Whether to expect the return value from Statement.executeUpdate() to indicate
109+
* whether the row was actually changed. If using MySQL and the connect string
110+
* has useAffectedRows=true set on it, then this can be used. It defaults to
111+
* false because it is MySQL-specific and requires explicitly enabling this in
112+
* the connect string.
113+
*/
114+
private boolean useAffectedRows = false;
115+
107116
/**
108117
* The registered method value caches. These allow you to quickly find
109118
* entities by the value of a given field.
@@ -201,6 +210,14 @@ public void configure(EnhancedProperties props)
201210
cacheMethodValues = props.getBoolean("CacheController.CacheMethodValues", false);
202211
cacheMethodValues = props.getBoolean("EntityStore.CacheMethodValues", cacheMethodValues);
203212

213+
// Whether to expect the return value from Statement.executeUpdate() to indicate
214+
// whether the row was actually changed.
215+
useAffectedRows = props.getBoolean("EntityStore.UseAffectedRows", useAffectedRows);
216+
if (useAffectedRows)
217+
{
218+
log.warn("EntityStore.UseAffectedRows is enabled, which REQUIRES that the database connection be configured so update statements return the count of affected rows. If unsure, disable this.");
219+
}
220+
204221
methodValueCaches = new HashMap<>();
205222

206223
// This should only happen when the application is reconfigured.
@@ -1061,20 +1078,25 @@ public <T extends Identifiable> void put(T entity)
10611078
throw new ControllerError("Cannot put null entity.");
10621079
}
10631080

1064-
getGroupSafe((Class<T>)entity.getClass()).put(entity);
1065-
1066-
// Update method value caches.
1067-
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
1068-
if (methodValueCache != null)
1069-
{
1070-
methodValueCache.update(entity.getId());
1071-
}
1072-
1073-
// Notify the listeners.
1074-
final CacheListener[] toNotify = listeners;
1075-
for (CacheListener listener : toNotify)
1081+
int rowsUpdated = getGroupSafe((Class<T>)entity.getClass()).put(entity);
1082+
1083+
// If useAffectedRows is enabled, then only update the methodValueCache and
1084+
// notify the listeners if an actual change was persisted.
1085+
if (!useAffectedRows || rowsUpdated > 0)
10761086
{
1077-
listener.cacheObjectExpired(entity.getClass(), entity.getId());
1087+
// Update method value caches.
1088+
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
1089+
if (methodValueCache != null)
1090+
{
1091+
methodValueCache.update(entity.getId());
1092+
}
1093+
1094+
// Notify the listeners.
1095+
final CacheListener[] toNotify = listeners;
1096+
for (CacheListener listener : toNotify)
1097+
{
1098+
listener.cacheObjectExpired(entity.getClass(), entity.getId());
1099+
}
10781100
}
10791101
}
10801102

@@ -1631,28 +1653,33 @@ public <T extends Identifiable> void putAll(Collection<T> objects)
16311653
{
16321654
Class<T> type = entry.getKey();
16331655
Collection<T> collection = entry.getValue();
1634-
1656+
16351657
// Update the group.
1636-
getGroupSafe(type).putAll(collection);
1637-
1638-
// Update method value caches.
1639-
MethodValueCache<T> methodValueCache =
1640-
(MethodValueCache<T>)methodValueCaches.get(type);
1641-
if (methodValueCache != null)
1658+
int rowsUpdated = getGroupSafe(type).putAll(collection);
1659+
1660+
// If useAffectedRows is enabled, then only update the methodValueCache and
1661+
// notify the listeners if an actual change was persisted.
1662+
if (!useAffectedRows || rowsUpdated > 0)
16421663
{
1643-
for (T object : collection)
1664+
// Update method value caches.
1665+
MethodValueCache<T> methodValueCache =
1666+
(MethodValueCache<T>)methodValueCaches.get(type);
1667+
if (methodValueCache != null)
16441668
{
1645-
methodValueCache.update(object.getId());
1669+
for (T object : collection)
1670+
{
1671+
methodValueCache.update(object.getId());
1672+
}
16461673
}
1647-
}
1648-
1649-
// Notify the listeners.
1650-
final CacheListener[] toNotify = listeners;
1651-
for (CacheListener listener : toNotify)
1652-
{
1653-
for (T object : collection)
1674+
1675+
// Notify the listeners.
1676+
final CacheListener[] toNotify = listeners;
1677+
for (CacheListener listener : toNotify)
16541678
{
1655-
listener.cacheObjectExpired(object.getClass(), object.getId());
1679+
for (T object : collection)
1680+
{
1681+
listener.cacheObjectExpired(object.getClass(), object.getId());
1682+
}
16561683
}
16571684
}
16581685
}

Diff for: gemini/src/main/java/com/techempower/cache/LruCacheGroup.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,27 @@ public TLongObjectMap<T> map()
144144
}
145145

146146
@Override
147-
public void put(T object)
147+
public int put(T object)
148148
{
149-
super.put(object);
149+
int rowsUpdated = super.put(object);
150150
objects.put(object.getId(), object);
151+
return rowsUpdated;
151152
}
152153

153154
@Override
154-
public void putAll(Collection<T> objectsToPut)
155+
public int putAll(Collection<T> objectsToPut)
155156
{
157+
int rowsUpdated = 0;
156158
for (T object : objectsToPut)
157159
{
158-
put(object);
160+
int c = put(object);
161+
if (c > 0)
162+
{
163+
// Only accumulate positive values;
164+
rowsUpdated += c;
165+
}
159166
}
167+
return rowsUpdated;
160168
}
161169

162170
@Override

Diff for: gemini/src/main/java/com/techempower/cache/PureMemoryGroup.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,21 @@ public static <T extends Identifiable> Builder<T> of(Class<T> type)
111111
* of entities.
112112
*/
113113
@Override
114-
protected void putPersistent(T object)
114+
protected int putPersistent(T object)
115115
{
116116
// Does nothing.
117+
return 0;
117118
}
118119

119120
/**
120121
* Specialization of CacheGroup.putAllPersistent to disable the persistence
121122
* of entities.
122123
*/
123124
@Override
124-
protected void putAllPersistent(Collection<T> objects)
125+
protected int putAllPersistent(Collection<T> objects)
125126
{
126127
// Does nothing.
128+
return 0;
127129
}
128130

129131
/**

0 commit comments

Comments
 (0)