- Every object "buffer" is serialized and a hashcode (checksum) of that buffer is created. If a directory for that buffer exists, I look if there is some buffer with the same length and, if there is, if it is identical, so avoiding to create a new one, or I create a new unique id, save the file and return the id and hashcode of that buffer. This is shared among all sessions, but as the data is read-only, there is no problem.
- The item 1 is the BufferId, not the ViewId. Now, with the bufferId, I try to find if a ViewState information in memory for the actual session which contains that bufferId. If none contains, a new ViewId is generated. If one exists, the Id of the old one is returned. Obviously, every time I reutilize a file, I do a keep-alive (in file, updating the date/time of the file, and in memory, calling GCUtils.KeepAlive).
- Every buffer is also kept in memory with weak-references, but to avoid recent buffers to be collected, I call GCUtils.KeepAlive. The GCUtils.KeepAlive (not GC.KeepAlive) guarantees that an object will survive the next collection.
- The ViewIds are created for the sessionId, so there is no problem of one user getting the viewstate of the other, even if the internal buffer is the same (in which case, every user will have different ViewIds, but they will point to the same buffer). Also, every page generates a NEW viewstate, and so I try to get the Id of an existing viewstate if possible, or I create a new file.
- By default, FileCachePersister runs a process at 30 minutes, deleting files with more than 4 hours. This has nothing to do with session-expiration times.
I will start explaining the CacheManager. The CacheManager class is responsible for loading and saving the buffers (bytes), as it does not know anything of the real type of the object. The most important thing is that it has is a WeakDictionary where the keys are the HashCodes of the buffers, and the values are Dictionaries of the Ids and the serialized bytes. Its internal functions try to find a value in memory using the hashcode and the buffer id and, if none is not found, ask for the persister to load it and then store the loaded value (if any) in these weak-dictionaries, doing a KeepAlive on them. The Save function does a similar process, trying to find a compatible buffer in memory, to reutilize the Id or, if one is not found, call the persister to save and return the generated Id.
Well, so, your create a Cache for an object. The cache serializes the object and calls CacheManager, which will try to reutilize the id of some identical buffer or will ask for it to be saved... but, where will it be saved?
Ok, in the FileCachePersister there is a thread to delete the old files, but that's nothing really complex.
Or, better, a cache to such value. Why? Because if you go from one page to another, generating identical viewstates, only a new "reference" to the buffer will be generated, but the buffer, which can be very large, is the same. It looks a little more complicated, as it has a Pair, but that's because of the way PageStatesPersisters works in general, as they only generate two objects, which the only purpose to be serialized. Not very friendly to be honest.
Look if the ViewState is in memory. If it is not, ask for the Persister to load it.
When saving, search one identical ViewState in memory, or create a new one, calling the persister to save it.
See full details: http://www.codeproject.com/KB/web-cache/PfzCaching.aspx