Microsoft KB Archive/884191

= Applications that use Caching Application Block may experience exceptions or may receive incorrect data from the cache =

Article ID: 884191

Article Last Modified on 5/18/2007

-

APPLIES TO


 * Microsoft .NET Framework 1.1
 * Microsoft .NET Framework 1.0

-





SYMPTOMS
Applications that use the Caching Application Block 1.0 (pre-Enterprise Library version) may experience exceptions or may receive incorrect data from the cache.



CAUSE
This problem occurs because multiple threads try to update the same cache item in a short time.

Note There are some known problems in Caching Application Block. These problems are explained in the &quot;More Information&quot; section.



WORKAROUND
To work around this problem, update your application to use the Enterprise Library version of the Caching Application Block. Alternatively, you can use an alternative caching mechanism, such as the Microsoft ASP.NET cache, or you can disable caching.



Exception safety
Data and metadata are processed separately in the old caching block. Data is added to the store synchronously as the user requests the data, but the metadata is added in a background thread. There is no error recovery code that returns the cache to a consistent state if either part of this two-phase process fails.

Thread safety
The original caching block protects itself against users who may call its API-level methods at the same time, but the protection is not extended down to the CacheService. The CacheService is an asynchronous subsystem in the cache that is responsible for all operations on metadata. These operations include storing and retrieving metadata from the cache's in-memory store and performing scavenging and expirations. There is no class that holds or describes the metadata, and the metadata is a series of unrelated data elements that are stored in different collections in the cache service. While the CacheService operates on this data, the CacheService locks each piece of data that it is accessing, but the CacheService never locks the metadata that is associated with a particular piece of cached data. If contention occurs between two or more threads, the data and the metadata that is stored in the cache may be out of sync. This scenario is more likely when the cache is more heavily used. If one cache transaction occurs each second, this scenario is unlikely to occur.

Persistent storage
Metadata is never updated in a persistent way. When the cache operates in a non-persistent mode, the cache starts with an empty cache every time. Data and metadata are added to the cache and are processed together from that point. As items are updated, their last accessed times are kept up-to-date in the scavenging and expiration metadata. If the cache is made persistent, the updates to the metadata are still made to the in-memory metadata and are never written back to the persistent store. If the cache is restarted, the existing data items are read from the persistent store as they are accessed, but metadata is read from the persistent store in its entirety at startup and is stored in-memory. All the timestamps that are used by scavenging and expirations are reset to their original at-creation values, and any indications of updates are lost. Because the indications of updates are lost, data may not expire when it should expire or items that are not correct may be scavenged because of last accessed timestamps that are not correct.

Another problem with persistent storage is that the behavior of the data in the cache is different in this mode when compared to in-memory caches. In-memory caches offer live object references. Therefore, any changes to an item that are made by a user after the data is retrieved from the cache are reflected when the same cache item is retrieved from the cache again. The object is live and changing, and those changed values are available through the cache. If the cache is persistent, a new instance of the object is created and returned every time the user requests the object. This fundamental difference in caching behavior between in-memory caches and persistent storage must be reflected in the user code.

