Sakai getAll caching is dangerous and cannot be supported by the Java cache standard (JSR-107)
GENERAL
TESTING
GENERAL
TESTING
Description
Sakai includes some methods in the Cache API which retrieve all the possible values in a cache. This is not supported by distributed caches because the nature of the cache is that it is not actually possible to determine what all the elements might be since they are spread across numerous nodes. Attempting to get them all would be very costly to the cache servers and would also cause problems with the refreshes since it would constantly make the entire cache appear active. This would basically guarantee a cache slam whenever the cache reaches the max TTL as all elements would flush at the same time and be reloaded.
Generally speaking, this use of caching means that Sakai cannot scale well in certain areas and we cannot go to a fully distributed cache (or a cache library that adheres to the standard and does not support this behavior).
This also requires there be extra cache functionality because the cache has to be marked to indicate it contains all the possible cache entries. It also has to be put into a "pause" state while loading all entries to avoid generating events.
For example: kernel/kernel-impl/src/main/java/org/sakaiproject/event/impl/BaseNotificationService.java List getNotifications(String function)
// if the cache is complete, use it if (m_cache.isComplete()) { notifications = m_cache.getAll(function); }
// otherwise get all the notifications from storage else { // Note: while we are getting from storage, storage might change. These can be processed // after we get the storage entries, and put them in the cache, and mark the cache complete. // -ggolden synchronized (m_cache) { // if we were waiting and it's now complete... if (m_cache.isComplete()) { notifications = m_cache.getAll(function); }
else { // save up any events to the cache until we get past this load m_cache.holdEvents();
// get them all for caching List all = m_storage.getAll();
// update the cache, and mark it complete for (int i = 0; i < all.size(); i++) { Notification notification = (Notification) all.get(i); m_cache.put(notification); }
m_cache.setComplete();
// get those for just this function notifications = m_cache.getAll(function);
// now we are complete, process any cached events m_cache.processEvents(); } } }
Sakai includes some methods in the Cache API which retrieve all the possible values in a cache. This is not supported by distributed caches because the nature of the cache is that it is not actually possible to determine what all the elements might be since they are spread across numerous nodes. Attempting to get them all would be very costly to the cache servers and would also cause problems with the refreshes since it would constantly make the entire cache appear active. This would basically guarantee a cache slam whenever the cache reaches the max TTL as all elements would flush at the same time and be reloaded.
Generally speaking, this use of caching means that Sakai cannot scale well in certain areas and we cannot go to a fully distributed cache (or a cache library that adheres to the standard and does not support this behavior).
This also requires there be extra cache functionality because the cache has to be marked to indicate it contains all the possible cache entries. It also has to be put into a "pause" state while loading all entries to avoid generating events.
For example:
kernel/kernel-impl/src/main/java/org/sakaiproject/event/impl/BaseNotificationService.java
List getNotifications(String function)
// if the cache is complete, use it
if (m_cache.isComplete())
{
notifications = m_cache.getAll(function);
}
// otherwise get all the notifications from storage
else
{
// Note: while we are getting from storage, storage might change. These can be processed
// after we get the storage entries, and put them in the cache, and mark the cache complete.
// -ggolden
synchronized (m_cache)
{
// if we were waiting and it's now complete...
if (m_cache.isComplete())
{
notifications = m_cache.getAll(function);
}
else
{
// save up any events to the cache until we get past this load
m_cache.holdEvents();
// get them all for caching
List all = m_storage.getAll();
// update the cache, and mark it complete
for (int i = 0; i < all.size(); i++)
{
Notification notification = (Notification) all.get(i);
m_cache.put(notification);
}
m_cache.setComplete();
// get those for just this function
notifications = m_cache.getAll(function);
// now we are complete, process any cached events
m_cache.processEvents();
}
}
}