Page MenuHomePhabricator

Cache management V2
Open, WishlistPublic

Description

Complete overhaul of the Cache management system. Benefits:

  • Better speed & internet consumption by using a lot less requests
  • Removal of almost all code duplication

Most of the code in Descriptor moves to CacheManager; Descriptor is renamed CachedObject.

Details:

interface CachedObject {
  // Updates this object with the JSON data
  update(JSON);

  // Marks this object as needing an update
  // (calls the corresponding CacheManager's update method)
  // (this is a convenience method)
  update();
}

abstract class CacheManager<D: Descriptor> {
  // The actual objects in the local cache
  internal cache: Map<ID, D>

  // The objects that need to be updated
  internal toUpdate: Set<D>

  // Time after which an object is either removed or updated
  internal expiresAfter

  // When the object expires, if it was used not too long ago, it is updated;
  // if it wasn't used in that time, it is deleted.
  internal activeTime

  // Gets the cached-version of the object(s)
  getCached(ID...)

  // Gets the object(s):
  // If they are NOT in the cache, blocks and requests the missing objects,
  // If they are in the cache and did not expire yet, takes them from the cache,
  // If they are in the cache and are expired, calls update() on them so they are cleaned on next run
  get(ID...)

  // Marks the objects as needing an update by adding them to the toUpdate set (but does not perform it, unless force=true)
  update(ID..., force = false)

  // The method that actually does the updates, which is usually called from another thread
  doUpdate()

  // The method that is called by all the others when a request is needed, it takes some IDs and calls the corresponding API endpoint and returns the JSON object.
  abstract doRequest()
}

Now, for each type of objects, the only code needed:

class User: CachedObject {
  // Data of a user...

  // Methods inherited by the interface
  update(JSON)
  update()
}

class Users: CacheManager<User> {
  // Inherited method
  doRequest(ID...)

  // All other inherited methods are already implemented
}

Event Timeline

CLOVIS triaged this task as Wishlist priority.Jan 4 2019, 4:41 PM
CLOVIS created this task.

@Info-Screen @WyldBot please give me your thoughts on this, this is a big change and I want to be sure it's good before beginning the implementation.

CLOVIS added a comment.Jan 4 2019, 9:35 PM

As suggested by Ruther, the non-blocking should be done by returning copies and updating the originals in the background, to avoid threading issues.

@Hackintosh5 you didn't comment on this yet, what do you think?

Tbh I think we need some system to inform the client when an object has been updated. So that the UI can be updated when an update is performed without closing and reopening something (if you close and reopen a page the old data is displayed because the UI is loaded before the cache is refreshed

CLOVIS added a comment.Wed, Jul 3, 4:05 PM

The idea here would be to never modify the objects, but instead just generate a new one and discard the old one, this way it can be done in parallel extremely easily

CLOVIS added a comment.Wed, Jul 3, 4:06 PM

Maybe a variable could be added to the objects to get its new version if there is one? So the UI can know when a new one is created

I meant a callback. So you pass a callback into the code to request an object, and it is called with the new object as the only parameter when the cache update is complete, if and only if the object is actually different