Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlt_calendarcache
[Package bdlt]

Provide an efficient cache for read-only bdlt::Calendar objects. More...

Namespaces

namespace  bdlt

Detailed Description

Outline
Purpose:
Provide an efficient cache for read-only bdlt::Calendar objects.
Classes:
bdlt::CalendarCache cache for read-only calendars that are loaded on demand
See also:
Component bdlt_calendar, Component bdlt_calendarloader
Description:
This component defines the bdlt::CalendarCache class, a cache for read-only bdlt::Calendar objects. The bdlt::CalendarCache class defines two methods for fetching calendars from the cache: a manipulator called getCalendar and an accessor called lookupCalendar. Calendars are identified by name using C-style strings, and both retrieval methods return a bsl::shared_ptr<const bdlt::Calendar>.
The first time a calendar is requested from the cache using the getCalendar manipulator, the identified calendar is loaded into the cache using the loader that was supplied upon construction of the cache (see bdlt_calendarloader); a reference to that newly-loaded calendar is then returned. Subsequent requests for the same calendar, using either the getCalendar or lookupCalendar method, are efficiently satisfied by returning references to the cached instance. The lookupCalendar accessor differs from the getCalendar manipulator in that when a request is made through the accessor for a calendar that is not present in the cache, the calendar is not loaded as a side-effect. In this case, an empty bsl::shared_ptr<const bdlt::Calendar> is returned instead, which is effectively a null pointer. Note that the calendar-naming convention in effect for a given cache is determined by the concrete loader supplied at construction of the cache.
Calendars stored in a cache can be explicitly invalidated; the invalidate method is used to invalidate a single calendar and invalidateAll invalidates all calendars in the cache. Invalidated calendars are removed from the cache. However, a calendar that has been invalidated in the cache remains valid to all outstanding references to it, obtained via earlier calls to the getCalendar and lookupCalendar methods, until all of those references have been destroyed. Note that a subsequent request, using the getCalendar manipulator, for a calendar that has been invalidated incurs the overhead of once again loading that calendar into the cache.
Calendars can also be invalidated on the basis of a timeout. To use this feature of bdlt::CalendarCache, a bsls::TimeInterval timeout must be supplied at construction. When a timeout is in effect for a cache, requests for a calendar from the cache using the getCalendar manipulator may incur the reloading of the calendar if the one in the cache has expired (i.e., the time interval defined by the timeout value has elapsed since the calendar was last loaded). In the case of the lookupCalendar accessor, an empty bsl::shared_ptr<const bdlt::Calendar> is returned if the requested calendar is found to have expired.
Thread Safety:
The bdlt::CalendarCache class is fully thread-safe (see bsldoc_glossary) provided that the allocator supplied at construction and the default allocator in effect during the lifetime of cache objects are both fully thread-safe.
Usage:
The following example illustrates how to use a bdlt::CalendarCache.
Example 1: Using a bdlt::CalendarCache:
This example shows basic use of a bdlt::CalendarCache object.
In this example, we assume a hypothetical calendar loader, MyCalendarLoader, the details of which are not important other than that it supports calendars identified by "DE", "FR", and "US", which nominally identify the major holidays in Germany, France, and the United States, respectively. Furthermore, we cite two specific dates of interest: 2011/07/04, which was a holiday in the US (Independence Day), but not in France, and 2011/07/14, which was a holiday in France (Bastille Day), but not in the US. Note that neither of these dates were holidays in Germany.
First, we create a calendar loader, an instance of MyCalendarLoader, and use it, in turn, to create a cache. For the purposes of this example, it is sufficient to let the cache use the default allocator:
  MyCalendarLoader    loader;
  bdlt::CalendarCache cache(&loader);
Next, we retrieve the calendar usA, identified by "US", verify that the loading of that calendar into the cache was successful (usA.get() is non-null), and verify that 2011/07/04 is recognized as a holiday in the "US" calendar, whereas 2011/07/14 is not:
  bsl::shared_ptr<const bdlt::Calendar> usA = cache.getCalendar("US");

                            assert( usA.get());
                            assert( usA->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert(!usA->isHoliday(bdlt::Date(2011, 7, 14)));
Then, we fetch the calendar identified by "FR", this time verifying that 2011/07/14 is recognized as a holiday in the "FR" calendar, but 2011/07/04 is not:
  bsl::shared_ptr<const bdlt::Calendar> frA = cache.getCalendar("FR");

                            assert( frA.get());
                            assert(!frA->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert( frA->isHoliday(bdlt::Date(2011, 7, 14)));
Next, we retrieve the "FR" calendar again, this time via the lookupCalendar accessor, and note that the request is satisfied by the calendar that is already in the cache:
  const bdlt::CalendarCache& readonlyCache = cache;

  bsl::shared_ptr<const bdlt::Calendar> frB =
                                          readonlyCache.lookupCalendar("FR");

                            assert( frA.get() == frB.get());
Then, we invalidate the "US" calendar in the cache and immediately fetch it again. The call to invalidate removed the "US" calendar from the cache, so it had to be reloaded into the cache to satisfy the request:
  int numInvalidated = cache.invalidate("US");
                            assert(1 == numInvalidated);

  bsl::shared_ptr<const bdlt::Calendar> usB = cache.getCalendar("US");

                            assert( usB.get() != usA.get());
                            assert( usB.get());
                            assert( usB->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert(!usB->isHoliday(bdlt::Date(2011, 7, 14)));
Next, all calendars in the cache are invalidated, then reloaded:
  numInvalidated = cache.invalidateAll();
                            assert(2 == numInvalidated);

  bsl::shared_ptr<const bdlt::Calendar> usC = cache.getCalendar("US");

                            assert( usC.get() != usA.get());
                            assert( usC.get() != usB.get());
                            assert( usC.get());
                            assert( usC->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert(!usC->isHoliday(bdlt::Date(2011, 7, 14)));

  bsl::shared_ptr<const bdlt::Calendar> frC = cache.getCalendar("FR");

                            assert( frC.get() != frA.get());
                            assert( frC.get() != frB.get());
                            assert( frC.get());
                            assert(!frC->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert( frC->isHoliday(bdlt::Date(2011, 7, 14)));
Now, verify that references to calendars that were invalidated in the cache are still valid for clients that obtained references to them before they were made invalid:
                            assert( usA->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert(!usA->isHoliday(bdlt::Date(2011, 7, 14)));

                            assert( usB->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert(!usB->isHoliday(bdlt::Date(2011, 7, 14)));

                            assert(!frA->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert( frA->isHoliday(bdlt::Date(2011, 7, 14)));

                            assert(!frB->isHoliday(bdlt::Date(2011, 7,  4)));
                            assert( frB->isHoliday(bdlt::Date(2011, 7, 14)));
When usA, usB, frA, and frB go out of scope, the resources used by the calendars to which they refer are automatically reclaimed.
Finally, using the lookupCalendar accessor, we attempt to retrieve a calendar that has not yet been loaded into the cache, but that we know to be supported by the calendar loader. Since the lookupCalendar accessor does not load calendars into the cache as a side-effect, the request fails:
  bsl::shared_ptr<const bdlt::Calendar> de =
                                          readonlyCache.lookupCalendar("DE");

                            assert(!de.get());
Example 2: A Calendar Cache with a Timeout:
This second example shows the effects on a bdlt::CalendarCache object that is constructed to have a timeout value. Note that the following snippets of code assume a platform-independent sleepSeconds method that sleeps for the specified number of seconds.
First, we create a calendar loader and a calendar cache. The cache is constructed to have a timeout of 3 seconds. Of course, such a short timeout is inappropriate for production use, but it is necessary for illustrating the effects of a timeout in this example. As in example 1 (above), we again let the cache use the default allocator:
  MyCalendarLoader           loader;
  bdlt::CalendarCache        cache(&loader, bsls::TimeInterval(3, 0));
  const bdlt::CalendarCache& readonlyCache = cache;
Next, we retrieve the calendar identified by "DE" from the cache:
  bsl::shared_ptr<const bdlt::Calendar> deA = cache.getCalendar("DE");

                            assert( deA.get());
Next, we sleep for 2 seconds before retrieving the "FR" calendar:
  sleepSeconds(2);

  bsl::shared_ptr<const bdlt::Calendar> frA = cache.getCalendar("FR");

                            assert( frA.get());
Next, we sleep for 2 more seconds before attempting to retrieve the "DE" calendar again, this time using the lookupCalendar accessor. Since the cumulative sleep time exceeds the timeout value established for the cache when it was constructed, the "DE" calendar has expired; hence, it has been removed from the cache:
  sleepSeconds(2);

  bsl::shared_ptr<const bdlt::Calendar> deB =
                                          readonlyCache.lookupCalendar("DE");

                            assert(!deB.get());
Next, we verify that the "FR" calendar is still available in the cache:
  bsl::shared_ptr<const bdlt::Calendar> frB =
                                          readonlyCache.lookupCalendar("FR");

                            assert( frA.get() == frB.get());
Finally, we sleep for an additional 2 seconds and verify that the "FR" calendar has also expired:
  sleepSeconds(2);

  bsl::shared_ptr<const bdlt::Calendar> frC =
                                          readonlyCache.lookupCalendar("FR");

                            assert(!frC.get());