BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlt_timetablecache.h
Go to the documentation of this file.
1/// @file bdlt_timetablecache.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_timetablecache.h -*-C++-*-
8#ifndef INCLUDED_BDLT_TIMETABLECACHE
9#define INCLUDED_BDLT_TIMETABLECACHE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_timetablecache bdlt_timetablecache
15/// @brief Provide an efficient cache for read-only `bdlt::Timetable` objects.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_timetablecache
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_timetablecache-purpose"> Purpose</a>
25/// * <a href="#bdlt_timetablecache-classes"> Classes </a>
26/// * <a href="#bdlt_timetablecache-description"> Description </a>
27/// * <a href="#bdlt_timetablecache-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlt_timetablecache-usage"> Usage </a>
29/// * <a href="#bdlt_timetablecache-example-1-using-a-bdlt-timetablecache"> Example 1: Using a bdlt::TimetableCache </a>
30/// * <a href="#bdlt_timetablecache-example-2-a-timetable-cache-with-a-timeout"> Example 2: A Timetable Cache with a Timeout </a>
31///
32/// # Purpose {#bdlt_timetablecache-purpose}
33/// Provide an efficient cache for read-only `bdlt::Timetable` objects.
34///
35/// # Classes {#bdlt_timetablecache-classes}
36///
37/// - bdlt::TimetableCache: cache for read-only timetables loaded on demand
38///
39/// @see bdlt_timetable, bdlt_timetableloader
40///
41/// # Description {#bdlt_timetablecache-description}
42/// This component defines the `bdlt::TimetableCache` class, a
43/// cache for read-only `bdlt::Timetable` objects. The `bdlt::TimetableCache`
44/// class defines two methods for fetching timetables from the cache: a
45/// manipulator called `getTimetable` and an accessor called `lookupTimetable`.
46/// Timetables are identified by name using C-style strings, and both retrieval
47/// methods return a `bsl::shared_ptr<const bdlt::Timetable>`.
48///
49/// The first time a timetable is requested from the cache using the
50/// `getTimetable` manipulator, the identified timetable is loaded into the
51/// cache using the loader that was supplied upon construction of the cache (see
52/// @ref bdlt_timetableloader ); a reference to that newly-loaded timetable is then
53/// returned. Subsequent requests for the same timetable, using either the
54/// `getTimetable` or `lookupTimetable` method, are efficiently satisfied by
55/// returning references to the cached instance. The `lookupTimetable` accessor
56/// differs from the `getTimetable` manipulator in that when a request is made
57/// through the accessor for a timetable that is *not* present in the cache, the
58/// timetable is not loaded as a side-effect. In this case, an empty
59/// `bsl::shared_ptr<const bdlt::Timetable>` is returned instead, which is
60/// effectively a null pointer. Note that the timetable-naming convention in
61/// effect for a given cache is determined by the concrete loader supplied at
62/// construction of the cache.
63///
64/// Timetables stored in a cache can be explicitly invalidated; the `invalidate`
65/// method is used to invalidate a single timetable and `invalidateAll`
66/// invalidates all timetables in the cache. Invalidated timetables are removed
67/// from the cache. However, a timetable that has been invalidated in the cache
68/// remains valid to all outstanding references to it, obtained via earlier
69/// calls to the `getTimetable` and `lookupTimetable` methods, until all of
70/// those references have been destroyed. Note that a subsequent request, using
71/// the `getTimetable` manipulator, for a timetable that has been invalidated
72/// incurs the overhead of once again loading that timetable into the cache.
73///
74/// Timetables can also be invalidated on the basis of a timeout. To use this
75/// feature of `bdlt::TimetableCache`, a `bsls::TimeInterval` timeout must be
76/// supplied at construction. When a timeout is in effect for a cache, requests
77/// for a timetable from the cache using the `getTimetable` manipulator may
78/// incur the reloading of the timetable if the one in the cache has expired
79/// (i.e., the time interval defined by the timeout value has elapsed since the
80/// timetable was last loaded). In the case of the `lookupTimetable` accessor,
81/// an empty `bsl::shared_ptr<const bdlt::Timetable>` is returned if the
82/// requested timetable is found to have expired.
83///
84/// ## Thread Safety {#bdlt_timetablecache-thread-safety}
85///
86///
87/// The `bdlt::TimetableCache` class is fully thread-safe (see
88/// @ref bsldoc_glossary ) provided that the allocator supplied at construction and
89/// the default allocator in effect during the lifetime of cache objects are
90/// both fully thread-safe.
91///
92/// ## Usage {#bdlt_timetablecache-usage}
93///
94///
95/// The following example illustrates how to use a `bdlt::TimetableCache`.
96///
97/// ### Example 1: Using a bdlt::TimetableCache {#bdlt_timetablecache-example-1-using-a-bdlt-timetablecache}
98///
99///
100/// This example shows basic use of a `bdlt::TimetableCache` object.
101///
102/// In this example, we assume a hypothetical timetable loader,
103/// `MyTimetableLoader`, the details of which are not important other than that
104/// it supports timetables identified by "ZERO", "ONE", and "TWO". Furthermore,
105/// the value of the initial transition code for each of these timetables is
106/// given by the timetable's name (e.g., if `Z` has the value of the timetable
107/// identified as "ZERO", then `0 == Z.initialTransitionCode()`).
108///
109/// First, we create a timetable loader, an instance of `MyTimetableLoader`, and
110/// use it, in turn, to create a cache. For the purposes of this example, it is
111/// sufficient to let the cache use the default allocator:
112/// @code
113/// MyTimetableLoader loader;
114/// bdlt::TimetableCache cache(&loader);
115/// @endcode
116/// Next, we retrieve the timetable `twoA`, identified by "TWO", verify that the
117/// loading of that timetable into the cache was successful (`twoA.get()` is
118/// non-null), and verify that 2 is the value of the initial transition code for
119/// timetable "TWO":
120/// @code
121/// bsl::shared_ptr<const bdlt::Timetable> twoA = cache.getTimetable("TWO");
122///
123/// assert(twoA.get());
124/// assert(2 == twoA->initialTransitionCode());
125/// @endcode
126/// Then, we fetch the timetable identified by "ONE", this time verifying that 1
127/// is the value of the initial transition code for the "ONE" timetable:
128/// @code
129/// bsl::shared_ptr<const bdlt::Timetable> oneA = cache.getTimetable("ONE");
130///
131/// assert(oneA.get());
132/// assert(1 == oneA->initialTransitionCode());
133/// @endcode
134/// Next, we retrieve the "ONE" timetable again, this time via the
135/// `lookupTimetable` accessor, and note that the request is satisfied by the
136/// timetable that is already in the cache:
137/// @code
138/// const bdlt::TimetableCache& readonlyCache = cache;
139///
140/// bsl::shared_ptr<const bdlt::Timetable> oneB =
141/// readonlyCache.lookupTimetable("ONE");
142///
143/// assert(oneA.get() == oneB.get());
144/// @endcode
145/// Then, we invalidate the "TWO" timetable in the cache and immediately fetch
146/// it again. The call to `invalidate` removed the "TWO" timetable from the
147/// cache, so it had to be reloaded into the cache to satisfy the request:
148/// @code
149/// int numInvalidated = cache.invalidate("TWO");
150/// assert(1 == numInvalidated);
151///
152/// bsl::shared_ptr<const bdlt::Timetable> twoB = cache.getTimetable("TWO");
153///
154/// assert(twoB.get() != twoA.get());
155/// assert(twoB.get());
156/// assert(2 == twoB->initialTransitionCode());
157/// @endcode
158/// Next, all timetables in the cache are invalidated, then reloaded:
159/// @code
160/// numInvalidated = cache.invalidateAll();
161/// assert(2 == numInvalidated);
162///
163/// bsl::shared_ptr<const bdlt::Timetable> twoC = cache.getTimetable("TWO");
164///
165/// assert(twoC.get() != twoA.get());
166/// assert(twoC.get() != twoB.get());
167/// assert(twoC.get());
168/// assert(2 == twoC->initialTransitionCode());
169///
170/// bsl::shared_ptr<const bdlt::Timetable> oneC = cache.getTimetable("ONE");
171///
172/// assert(oneC.get() != oneA.get());
173/// assert(oneC.get() != oneB.get());
174/// assert(oneC.get());
175/// assert(1 == oneC->initialTransitionCode());
176/// @endcode
177/// Now, verify that references to timetables that were invalidated in the cache
178/// are still valid for clients that obtained references to them before they
179/// were made invalid:
180/// @code
181/// assert(1 == oneA->initialTransitionCode());
182/// assert(1 == oneB->initialTransitionCode());
183///
184/// assert(2 == twoA->initialTransitionCode());
185/// assert(2 == twoB->initialTransitionCode());
186/// @endcode
187/// When `twoA`, `twoB`, `oneA`, and `oneB` go out of scope, the resources used
188/// by the timetables to which they refer are automatically reclaimed.
189///
190/// Finally, using the `lookupTimetable` accessor, we attempt to retrieve a
191/// timetable that has not yet been loaded into the cache, but that we *know* to
192/// be supported by the timetable loader. Since the `lookupTimetable` accessor
193/// does not load timetables into the cache as a side-effect, the request fails:
194/// @code
195/// bsl::shared_ptr<const bdlt::Timetable> zero =
196/// readonlyCache.lookupTimetable("ZERO");
197///
198/// assert(!zero.get());
199/// @endcode
200///
201/// ### Example 2: A Timetable Cache with a Timeout {#bdlt_timetablecache-example-2-a-timetable-cache-with-a-timeout}
202///
203///
204/// This second example shows the effects on a `bdlt::TimetableCache` object
205/// that is constructed to have a timeout value. Note that the following
206/// snippets of code assume a platform-independent `sleepSeconds` method that
207/// sleeps for the specified number of seconds.
208///
209/// First, we create a timetable loader and a timetable cache. The cache is
210/// constructed to have a timeout of 3 seconds. Of course, such a short timeout
211/// is inappropriate for production use, but it is necessary for illustrating
212/// the effects of a timeout in this example. As in example 1 (above), we again
213/// let the cache use the default allocator:
214/// @code
215/// MyTimetableLoader loader;
216/// bdlt::TimetableCache cache(&loader, bsls::TimeInterval(3, 0));
217/// const bdlt::TimetableCache& readonlyCache = cache;
218/// @endcode
219/// Next, we retrieve the timetable identified by "ZERO" from the cache:
220/// @code
221/// bsl::shared_ptr<const bdlt::Timetable> zeroA = cache.getTimetable("ZERO");
222///
223/// assert(zeroA.get());
224/// @endcode
225/// Next, we sleep for 2 seconds before retrieving the "ONE" timetable:
226/// @code
227/// sleepSeconds(2);
228///
229/// bsl::shared_ptr<const bdlt::Timetable> oneA = cache.getTimetable("ONE");
230///
231/// assert(oneA.get());
232/// @endcode
233/// Next, we sleep for 2 more seconds before attempting to retrieve the "ZERO"
234/// timetable again, this time using the `lookupTimetable` accessor. Since the
235/// cumulative sleep time exceeds the timeout value established for the cache
236/// when it was constructed, the "ZERO" timetable has expired; hence, it has
237/// been removed from the cache:
238/// @code
239/// sleepSeconds(2);
240///
241/// bsl::shared_ptr<const bdlt::Timetable> zeroB =
242/// readonlyCache.lookupTimetable("ZERO");
243///
244/// assert(!zeroB.get());
245/// @endcode
246/// Next, we verify that the "ONE" timetable is still available in the cache:
247/// @code
248/// bsl::shared_ptr<const bdlt::Timetable> oneB =
249/// readonlyCache.lookupTimetable("ONE");
250///
251/// assert(oneA.get() == oneB.get());
252/// @endcode
253/// Finally, we sleep for an additional 2 seconds and verify that the "ONE"
254/// timetable has also expired:
255/// @code
256/// sleepSeconds(2);
257///
258/// bsl::shared_ptr<const bdlt::Timetable> oneC =
259/// readonlyCache.lookupTimetable("ONE");
260///
261/// assert(!oneC.get());
262/// @endcode
263/// @}
264/** @} */
265/** @} */
266
267/** @addtogroup bdl
268 * @{
269 */
270/** @addtogroup bdlt
271 * @{
272 */
273/** @addtogroup bdlt_timetablecache
274 * @{
275 */
276
277#include <bdlscm_version.h>
278
279#include <bdlt_timetable.h>
280#include <bdlt_datetime.h>
282
283#include <bslma_allocator.h>
285
287
288#include <bslmt_mutex.h>
289
290#include <bsls_timeinterval.h>
291
292#include <bsl_map.h>
293#include <bsl_memory.h> // 'bsl::shared_ptr'
294#include <bsl_string.h>
295
296
297namespace bdlt {
298
299class TimetableLoader;
300class TimetableCache_Entry;
301
302 // ==========================
303 // class TimetableCache_Entry
304 // ==========================
305
306// IMPLEMENTATION NOTE: The Sun Studio 12.3 compiler does not support 'map's
307// holding types that are incomplete at the point of declaration of a data
308// member. Other compilers allow us to complete 'TimetableCache_Entry' at a
309// later point in the code, but before any operation (such as 'insert') that
310// would require the type to be complete. If we did not have to support this
311// compiler, this whole class could be defined in the .cpp file; as it stands,
312// it *must* be defined before class 'TimetableCache'.
313
314/// This class defines the type of objects that are inserted into the
315/// timetable cache. Each entry contains a shared pointer to a read-only timetable and the time at which that timetable was loaded.
316///
317/// \note Note that an
318/// explicit allocator is *required* to create an entry object.
319///
320/// See @ref bdlt_timetablecache
322
323 // DATA
324 bsl::shared_ptr<const Timetable> d_ptr; // shared pointer to
325 // out-of-place instance
326
327 Datetime d_loadTime; // time when timetable was
328 // loaded
329
330 public:
331 // CREATORS
332
333 /// Create an empty cache entry object.
334 /// \note Note that an empty cache entry
335 /// is never actually inserted into the cache.
337
338 /// Create a cache entry object for managing the specified `timetable`
339 /// that was loaded at the specified `loadTime` using the specified `allocator`.
340 ///
341 /// \pre The behavior is undefined unless `timetable` uses
342 /// `allocator` to obtain memory.
344 const Datetime& loadTime,
345 bslma::Allocator *allocator);
346
347 /// Create a cache entry object having the value of the specified
348 /// `original` object.
350
351 /// Destroy this cache entry object.
353
354 // MANIPULATORS
355
356 /// Assign to this cache entry object the value of the specified `rhs`
357 /// object, and return a reference providing modifiable access to this
358 /// object.
360
361 // ACCESSORS
362
363 /// Return a shared pointer providing non-modifiable access to the
364 /// timetable referred to by this cache entry object.
366
367 /// Return the time at which the timetable referred to by this cache
368 /// entry object was loaded.
370};
371
372 // ====================
373 // class TimetableCache
374 // ====================
375
376/// This class implements an efficient cache of *read-only*
377/// `bdlt::Timetable` objects that are loaded into the cache, using a
378/// timetable loader supplied at construction, as a side-effect of the
379/// `getTimetable` manipulator. Timetables in the cache can be invalidated,
380/// and removed from the cache via the `invalidate` and `invalidateAll`
381/// methods. In addition, timetables in the cache can be made to expire
382/// based on a timeout that may be optionally supplied at construction. The
383/// `bsl::shared_ptr<const bdlt::Timetable>` objects returned from the
384/// `getTimetable` and `lookupTimetable` methods allow for the safe removal
385/// of timetables from the cache that may still have outstanding references
386/// to them.
387///
388/// This container is *exception* *neutral* with no guarantee of rollback:
389/// if an exception is thrown during the invocation of a method on a
390/// pre-existing instance, the container is left in a valid state, but its
391/// value is undefined. In no event is memory leaked.
392///
393/// This class is fully thread-safe (see @ref bsldoc_glossary ).
394///
395/// See @ref bdlt_timetablecache
397
398 // DATA
400 d_cache; // cache of (name, handle) pairs
401
402 TimetableLoader *d_loader_p; // timetable loader (held, not
403 // owned)
404
405 DatetimeInterval d_timeOut; // timeout value; ignored unless
406 // 'd_hasTimeOutFlag' is 'true'
407
408 bool d_hasTimeOutFlag; // 'true' if this cache has a
409 // timeout value and 'false'
410 // otherwise
411
412 mutable bslmt::Mutex d_lock; // guard access to cache
413
414 bslma::Allocator *d_allocator_p; // memory allocator (held, not
415 // owned)
416
417 private:
418 // PRIVATE TYPES
420 CacheIterator;
421
423 ConstCacheIterator;
424
425 private:
426 // NOT IMPLEMENTED
428 TimetableCache& operator=(const TimetableCache&);
429
430 public:
431 // TRAITS
432
434
435 // CREATORS
436
437 /// Create an empty timetable cache that uses the specified `loader` to
438 /// load timetables on demand and has no timeout. Optionally specify a
439 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
440 /// the currently installed default allocator is used. Timetables
441 /// loaded into this cache remain valid for retrieval until they have
442 /// been explicitly invalidated (via either the `invalidate` or
443 /// `invalidateAll` methods), or until this object is destroyed.
444 ///
445 /// \pre The behavior is undefined unless `loader` remains valid throughout the
446 /// lifetime of this cache.
447 explicit
449 bslma::Allocator *basicAllocator = 0);
450
451 /// Create an empty timetable cache that uses the specified `loader` to
452 /// load timetables on demand and has the specified `timeout` interval
453 /// indicating the length of time that timetables remain valid for
454 /// subsequent retrieval from the cache after they have been loaded.
455 /// Optionally specify a `basicAllocator` used to supply memory. If
456 /// `basicAllocator` is 0, the currently installed default allocator is used.
457 ///
458 /// \pre The behavior is undefined unless
459 /// `bsls::TimeInterval() <= timeout <= bsls::TimeInterval(INT_MAX, 0)`,
460 /// and `loader` remains valid throughout the lifetime of this cache.
461 ///
462 /// \note Note that a `timeout` value of 0 indicates that a timetable will be
463 /// loaded into the cache by *each* (successful) call to the
464 /// `getTimetable` method.
466 const bsls::TimeInterval& timeout,
467 bslma::Allocator *basicAllocator = 0);
468
469 /// Destroy this object.
471
472 // MANIPULATORS
473
474 /// Return a shared pointer providing non-modifiable access to the
475 /// timetable having the specified `timetableName` in this timetable
476 /// cache, loading the timetable into the cache using the loader that
477 /// was supplied at construction if the timetable is not already present
478 /// in the cache or if the timetable has expired (i.e., per a timeout
479 /// optionally supplied at construction). If the loader fails, whether
480 /// in loading a timetable for the first time or in reloading a
481 /// timetable that has expired, return an empty shared pointer.
483
484 /// Invalidate the timetable having the specified `timetableName` in
485 /// this timetable cache, and remove it from the cache. If a timetable
486 /// having `timetableName` is not present in this cache, this method has
487 /// no effect. Return the number of timetables that were invalidated.
488 ///
489 /// \note Note that a timetable that has been invalidated in the cache remains
490 /// valid to all outstanding references to it, obtained via earlier
491 /// calls to the `getTimetable` and `lookupTimetable` methods, until all
492 /// of those references have been destroyed.
493 int invalidate(const char *timetableName);
494
495 /// Invalidate all timetables in this timetable cache, and remove them
496 /// from the cache. Return the number of timetables that were invalidated.
497 ///
498 /// \note Note that a timetable that has been invalidated in the
499 /// cache remains valid to all outstanding references to it, obtained
500 /// via earlier calls to the `getTimetable` and `lookupTimetable`
501 /// methods, until all of those references have been destroyed.
503
504 // ACCESSORS
505
506 /// Return a shared pointer providing non-modifiable access to the
507 /// timetable having the specified `timetableName` in this timetable
508 /// cache. If the timetable having `timetableName` is not found in the
509 /// cache, or if the timetable has expired (i.e., per a timeout
510 /// optionally supplied at construction), return an empty shared
511 /// pointer.
513 lookupTimetable(const char *timetableName) const;
514
515 /// Return the datetime, in Coordinated Universal Time (UTC), at which
516 /// the timetable having the specified `timetableName` was loaded into
517 /// this timetable cache. If the timetable having `timetableName` is
518 /// not found in the cache, or if the timetable has expired (i.e., per a
519 /// timeout optionally supplied at construction), return `Datetime()`.
520 Datetime lookupLoadTime(const char *timetableName) const;
521};
522
523// ============================================================================
524// INLINE DEFINITIONS
525// ============================================================================
526
527} // close package namespace
528
529
530#endif
531
532// ----------------------------------------------------------------------------
533// Copyright 2018 Bloomberg Finance L.P.
534//
535// Licensed under the Apache License, Version 2.0 (the "License");
536// you may not use this file except in compliance with the License.
537// You may obtain a copy of the License at
538//
539// http://www.apache.org/licenses/LICENSE-2.0
540//
541// Unless required by applicable law or agreed to in writing, software
542// distributed under the License is distributed on an "AS IS" BASIS,
543// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
544// See the License for the specific language governing permissions and
545// limitations under the License.
546// ----------------------------- END-OF-FILE ----------------------------------
547
548/** @} */
549/** @} */
550/** @} */
Definition bdlt_datetimeinterval.h:201
Definition bdlt_datetime.h:330
Definition bdlt_timetablecache.h:321
TimetableCache_Entry()
bsl::shared_ptr< const Timetable > get() const
TimetableCache_Entry(const TimetableCache_Entry &original)
Datetime loadTime() const
~TimetableCache_Entry()
Destroy this cache entry object.
TimetableCache_Entry & operator=(const TimetableCache_Entry &rhs)
TimetableCache_Entry(Timetable *timetable, const Datetime &loadTime, bslma::Allocator *allocator)
Definition bdlt_timetablecache.h:396
BSLMF_NESTED_TRAIT_DECLARATION(TimetableCache, bslma::UsesBslmaAllocator)
TimetableCache(TimetableLoader *loader, const bsls::TimeInterval &timeout, bslma::Allocator *basicAllocator=0)
~TimetableCache()
Destroy this object.
int invalidate(const char *timetableName)
Datetime lookupLoadTime(const char *timetableName) const
bsl::shared_ptr< const Timetable > getTimetable(const char *timetableName)
TimetableCache(TimetableLoader *loader, bslma::Allocator *basicAllocator=0)
bsl::shared_ptr< const Timetable > lookupTimetable(const char *timetableName) const
Definition bdlt_timetableloader.h:340
Definition bdlt_timetable.h:680
Definition bslstl_map.h:653
BloombergLP::bslstl::TreeIterator< const value_type, Node, difference_type > const_iterator
Definition bslstl_map.h:758
BloombergLP::bslstl::TreeIterator< value_type, Node, difference_type > iterator
Definition bslstl_map.h:756
Definition bslstl_sharedptr.h:1838
Definition bslma_allocator.h:545
Definition bslmt_mutex.h:317
Definition bsls_timeinterval.h:307
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bbldc_basicisma30360.h:112
Definition bslma_usesbslmaallocator.h:344