Skip to content

Commit

Permalink
Merge pull request #99 from k-r-g/CacheMessageManager_MethodValueCach…
Browse files Browse the repository at this point in the history
…e_Updates

Make CacheMessageManager support the EntityStore method value cache
  • Loading branch information
msmith-techempower authored Oct 2, 2020
2 parents f00a790 + 5ca11e7 commit 772165f
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 23 deletions.
64 changes: 45 additions & 19 deletions gemini/src/main/java/com/techempower/cache/EntityStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,45 @@ protected <T extends Identifiable> boolean isIndexed(Class<T> type, String metho
}
}

/**
* Whether the provided class uses the @Indexed annotation and therefore uses
* the method value cache.
*/
public boolean usesMethodValueCache(Class<? extends Identifiable> type)
{
return methodValueCaches.get(type) != null;
}

/**
* Update the specified method value cache.
*/
public void methodValueCacheUpdate(Class<? extends Identifiable> type, long... ids)
{
final MethodValueCache<?> methodValueCache = methodValueCaches.get(type);
if (methodValueCache != null)
{
for (long id : ids)
{
methodValueCache.update(id);
}
}
}

/**
* Delete from the specified method value cache.
*/
public void methodValueCacheDelete(Class<? extends Identifiable> type, long... ids)
{
final MethodValueCache<?> methodValueCache = methodValueCaches.get(type);
if (methodValueCache != null)
{
for (long id : ids)
{
methodValueCache.delete(id);
}
}
}

/**
* Reset all entity groups controlled by this controller.
*/
Expand Down Expand Up @@ -1028,14 +1067,9 @@ public <T extends Identifiable> T get(Class<T> type, String methodName, Object v
public void refresh(Class<? extends Identifiable> type, long... ids)
{
getGroupSafe(type).refresh(ids);

final MethodValueCache<?> methodValueCache = methodValueCaches.get(type);
if (methodValueCache != null)
{
for (long id : ids) {
methodValueCache.update(id);
}
}

// Update index/methodValueCache.
methodValueCacheUpdate(type, ids);

// Notify the listeners.
notifyListenersCacheObjectExpired(true, type, ids);
Expand Down Expand Up @@ -1085,11 +1119,7 @@ public <T extends Identifiable> void put(T entity)
if (!useAffectedRows || rowsUpdated > 0)
{
// Update method value caches.
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
if (methodValueCache != null)
{
methodValueCache.update(entity.getId());
}
methodValueCacheUpdate(entity.getClass(), entity.getId());

// Notify the listeners.
final CacheListener[] toNotify = listeners;
Expand Down Expand Up @@ -1133,12 +1163,8 @@ public <T extends Identifiable> void remove(T entity)
}

// Update method value cache.
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
if (methodValueCache != null)
{
methodValueCache.delete(entity.getId());
}

methodValueCacheDelete(entity.getClass(), entity.getId());

// Notify the listeners.
final CacheListener[] toNotify = listeners;
for (CacheListener listener : toNotify)
Expand Down
16 changes: 12 additions & 4 deletions gemini/src/main/java/com/techempower/cache/annotation/Indexed.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,18 @@
import java.lang.annotation.*;

/**
* This annotation is used to mark entity classes or methods as indexed.
* Classes or methods marked as @Indexed should always cache method values,
* even if method value caching is turned off.
* This annotation is used to mark entity classes or methods as indexed. Classes
* or methods marked as @Indexed should always cache method values, even if
* method value caching is turned off.
* <p>
* <b>IMPORTANT</b>: If you use this annotation in an application that uses the
* CacheMessageManager to distribute cache updates to other instances, it is
* your responsibility to ensure that your corresponding EntityGroup
* ("distribute" defaulting to false) or CacheGroup ("distribute" defaulting to
* true) has the "distribute" flag set to true. Otherwise each instance will
* risk having a stale method value cache and you'll get wrong answers from
* EntityStore.get() and list() and honestly it won't be very fun.
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Indexed { }
14 changes: 14 additions & 0 deletions gemini/src/main/java/com/techempower/data/EntityGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -2269,6 +2269,13 @@ public static class Builder<T extends Identifiable>
* need to notify DistributionListeners. However, if some instances use a
* CacheGroup for this entity, then it may be useful to set this to true so
* those instances can update their cache.
* <p>
* <b>IMPORTANT</b>: If you use the @Indexed annotation on this entity in an
* application that uses the CacheMessageManager to distribute cache updates to
* other instances, it is your responsibility to ensure that "distribute" is set
* to true. Otherwise each instance will risk having a stale method value cache
* and you'll get wrong answers from EntityStore.get() and list() and it
* honestly won't be very fun.
*/
protected boolean distribute = false;

Expand Down Expand Up @@ -2364,6 +2371,13 @@ public Builder<T> readOnly()
/**
* Specifies updates to the resulting EntityGroup should be passed to
* DistributionListeners.
* <p>
* <b>IMPORTANT</b>: If you use the @Indexed annotation on this entity in an
* application that uses the CacheMessageManager to distribute cache updates to
* other instances, it is your responsibility to ensure that "distribute" is set
* to true. Otherwise each instance will risk having a stale method value cache
* and you'll get wrong answers from EntityStore.get() and list() and it
* honestly won't be very fun.
*/
public Builder<T> distribute(boolean distribute)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,9 @@ else if (group instanceof EntityGroup)
log.info("Receiving 'cache object expired' but group id is invalid:{}, group: {}",
cacheMessage, group);
}
// Now that the object is updated in the cache, update the method value cache if
// needed.
store.methodValueCacheUpdate(group.getType(), cacheMessage.getObjectId());

break;
}
Expand All @@ -514,6 +517,9 @@ else if (group instanceof EntityGroup)
"invalid: {}, group: {}, cacheMessage: {}",
cacheMessage.getGroupId(), group, cacheMessage);
}
// Now that the object is deleted from the cache, also delete from the method
// value cache if needed.
store.methodValueCacheDelete(group.getType(), cacheMessage.getObjectId());
break;
}
case (CacheMessage.ACTION_GROUP_RESET):
Expand Down

0 comments on commit 772165f

Please sign in to comment.