From: Brian Candler Date: 2003-07-17T07:27:10+09:00 Subject: Re: OO Design question for Net::HTTP caching extension On Thu, Jul 17, 2003 at 07:13:34AM +0900, Aredridel wrote: > I'm in the process of writing an HTTP-1.1 extension to Net::HTTP. At > the moment, I'm replacing Net::HTTP#get with a version that will check > for a valid cache entry and return that instead of the fresh result, and > the original, uncached functionality is in #get_fresh > > At the moment, I've made the cache per-class: A single class variable > for the cache, something like Net::HTTP.cache = new Net::HTTPCache, then > the new functionality starts. > > Is this sane? Should it be an instance variable instead of a class > variable? Is there a more orthagonal way to do this? One architectural suggestion: rather than extending/overriding Net::HTTP, make your cache a separate object. Then, Net::Cache#get can return an object from its cache (which is just an instance variable of Net::Cache), and also contains instances of object(s) which do the fetching from remote hosts when there is a cache miss. I think there are a number of advantages in this approach: - no messing with an existing foundation class - the potential to have multiple methods for retrieving objects (e.g. Net::FTP as well as Net::HTTP) - a clear division of responsibility between the cache and the object retrieval protocol With some care, you should be able to make your cache thread-safe: if a request for object X comes in while the cache is already fetching that object, it could wait until the retrieval is complete. The cache can then sit behind DRb, for example, so it can be accessed by multiple processes simultaneously. Equally, if you get a request for object Y while a fetch for object X is taking place, you can perform a parallel fetch in another thread. I think it would be much easier to deal with these sort of threading issues when the cache is a separate object from the protocol. In fact, I think I would break it up a bit more: have the raw cache as one object (very simple: just 'put' and 'fetch' methods into a hash, but it has its own semaphore for protecting concurrent accesses), and a cache manager which takes the incoming 'get' requests, checks the cache, and if necessary performs the actual fetch before returning the object. Regards, Brian.