BDE 4.14.0 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
316/// timetable and the time at which that timetable was loaded. Note that an
317/// explicit allocator is *required* to create an entry object.
318///
319/// See @ref bdlt_timetablecache
321
322 // DATA
323 bsl::shared_ptr<const Timetable> d_ptr; // shared pointer to
324 // out-of-place instance
325
326 Datetime d_loadTime; // time when timetable was
327 // loaded
328
329 public:
330 // CREATORS
331
332 /// Create an empty cache entry object. Note that an empty cache entry
333 /// is never actually inserted into the cache.
335
336 /// Create a cache entry object for managing the specified `timetable`
337 /// that was loaded at the specified `loadTime` using the specified
338 /// `allocator`. The behavior is undefined unless `timetable` uses
339 /// `allocator` to obtain memory.
341 const Datetime& loadTime,
342 bslma::Allocator *allocator);
343
344 /// Create a cache entry object having the value of the specified
345 /// `original` object.
347
348 /// Destroy this cache entry object.
350
351 // MANIPULATORS
352
353 /// Assign to this cache entry object the value of the specified `rhs`
354 /// object, and return a reference providing modifiable access to this
355 /// object.
357
358 // ACCESSORS
359
360 /// Return a shared pointer providing non-modifiable access to the
361 /// timetable referred to by this cache entry object.
363
364 /// Return the time at which the timetable referred to by this cache
365 /// entry object was loaded.
367};
368
369 // ====================
370 // class TimetableCache
371 // ====================
372
373/// This class implements an efficient cache of *read-only*
374/// `bdlt::Timetable` objects that are loaded into the cache, using a
375/// timetable loader supplied at construction, as a side-effect of the
376/// `getTimetable` manipulator. Timetables in the cache can be invalidated,
377/// and removed from the cache via the `invalidate` and `invalidateAll`
378/// methods. In addition, timetables in the cache can be made to expire
379/// based on a timeout that may be optionally supplied at construction. The
380/// `bsl::shared_ptr<const bdlt::Timetable>` objects returned from the
381/// `getTimetable` and `lookupTimetable` methods allow for the safe removal
382/// of timetables from the cache that may still have outstanding references
383/// to them.
384///
385/// This container is *exception* *neutral* with no guarantee of rollback:
386/// if an exception is thrown during the invocation of a method on a
387/// pre-existing instance, the container is left in a valid state, but its
388/// value is undefined. In no event is memory leaked.
389///
390/// This class is fully thread-safe (see @ref bsldoc_glossary ).
391///
392/// See @ref bdlt_timetablecache
394
395 // DATA
397 d_cache; // cache of (name, handle) pairs
398
399 TimetableLoader *d_loader_p; // timetable loader (held, not
400 // owned)
401
402 DatetimeInterval d_timeOut; // timeout value; ignored unless
403 // 'd_hasTimeOutFlag' is 'true'
404
405 bool d_hasTimeOutFlag; // 'true' if this cache has a
406 // timeout value and 'false'
407 // otherwise
408
409 mutable bslmt::Mutex d_lock; // guard access to cache
410
411 bslma::Allocator *d_allocator_p; // memory allocator (held, not
412 // owned)
413
414 private:
415 // PRIVATE TYPES
417 CacheIterator;
418
420 ConstCacheIterator;
421
422 private:
423 // NOT IMPLEMENTED
425 TimetableCache& operator=(const TimetableCache&);
426
427 public:
428 // CREATORS
429
430 /// Create an empty timetable cache that uses the specified `loader` to
431 /// load timetables on demand and has no timeout. Optionally specify a
432 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
433 /// the currently installed default allocator is used. Timetables
434 /// loaded into this cache remain valid for retrieval until they have
435 /// been explicitly invalidated (via either the `invalidate` or
436 /// `invalidateAll` methods), or until this object is destroyed. The
437 /// behavior is undefined unless `loader` remains valid throughout the
438 /// lifetime of this cache.
439 explicit
441 bslma::Allocator *basicAllocator = 0);
442
443 /// Create an empty timetable cache that uses the specified `loader` to
444 /// load timetables on demand and has the specified `timeout` interval
445 /// indicating the length of time that timetables remain valid for
446 /// subsequent retrieval from the cache after they have been loaded.
447 /// Optionally specify a `basicAllocator` used to supply memory. If
448 /// `basicAllocator` is 0, the currently installed default allocator is
449 /// used. The behavior is undefined unless
450 /// `bsls::TimeInterval() <= timeout <= bsls::TimeInterval(INT_MAX, 0)`,
451 /// and `loader` remains valid throughout the lifetime of this cache.
452 /// Note that a `timeout` value of 0 indicates that a timetable will be
453 /// loaded into the cache by *each* (successful) call to the
454 /// `getTimetable` method.
456 const bsls::TimeInterval& timeout,
457 bslma::Allocator *basicAllocator = 0);
458
459 /// Destroy this object.
461
462 // MANIPULATORS
463
464 /// Return a shared pointer providing non-modifiable access to the
465 /// timetable having the specified `timetableName` in this timetable
466 /// cache, loading the timetable into the cache using the loader that
467 /// was supplied at construction if the timetable is not already present
468 /// in the cache or if the timetable has expired (i.e., per a timeout
469 /// optionally supplied at construction). If the loader fails, whether
470 /// in loading a timetable for the first time or in reloading a
471 /// timetable that has expired, return an empty shared pointer.
473
474 /// Invalidate the timetable having the specified `timetableName` in
475 /// this timetable cache, and remove it from the cache. If a timetable
476 /// having `timetableName` is not present in this cache, this method has
477 /// no effect. Return the number of timetables that were invalidated.
478 /// Note that a timetable that has been invalidated in the cache remains
479 /// valid to all outstanding references to it, obtained via earlier
480 /// calls to the `getTimetable` and `lookupTimetable` methods, until all
481 /// of those references have been destroyed.
482 int invalidate(const char *timetableName);
483
484 /// Invalidate all timetables in this timetable cache, and remove them
485 /// from the cache. Return the number of timetables that were
486 /// invalidated. Note that a timetable that has been invalidated in the
487 /// cache remains valid to all outstanding references to it, obtained
488 /// via earlier calls to the `getTimetable` and `lookupTimetable`
489 /// methods, until all of those references have been destroyed.
491
492 // ACCESSORS
493
494 /// Return a shared pointer providing non-modifiable access to the
495 /// timetable having the specified `timetableName` in this timetable
496 /// cache. If the timetable having `timetableName` is not found in the
497 /// cache, or if the timetable has expired (i.e., per a timeout
498 /// optionally supplied at construction), return an empty shared
499 /// pointer.
501 lookupTimetable(const char *timetableName) const;
502
503 /// Return the datetime, in Coordinated Universal Time (UTC), at which
504 /// the timetable having the specified `timetableName` was loaded into
505 /// this timetable cache. If the timetable having `timetableName` is
506 /// not found in the cache, or if the timetable has expired (i.e., per a
507 /// timeout optionally supplied at construction), return `Datetime()`.
508 Datetime lookupLoadTime(const char *timetableName) const;
509};
510
511// ============================================================================
512// INLINE DEFINITIONS
513// ============================================================================
514
515} // close package namespace
516
517
518// TRAITS
519
520
521namespace bslma {
522
523template <>
524struct UsesBslmaAllocator<bdlt::TimetableCache> : bsl::true_type {};
525
526} // close namespace bslma
527
528
529#endif
530
531// ----------------------------------------------------------------------------
532// Copyright 2018 Bloomberg Finance L.P.
533//
534// Licensed under the Apache License, Version 2.0 (the "License");
535// you may not use this file except in compliance with the License.
536// You may obtain a copy of the License at
537//
538// http://www.apache.org/licenses/LICENSE-2.0
539//
540// Unless required by applicable law or agreed to in writing, software
541// distributed under the License is distributed on an "AS IS" BASIS,
542// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
543// See the License for the specific language governing permissions and
544// limitations under the License.
545// ----------------------------- END-OF-FILE ----------------------------------
546
547/** @} */
548/** @} */
549/** @} */
Definition bdlt_datetimeinterval.h:201
Definition bdlt_datetime.h:331
Definition bdlt_timetablecache.h:320
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:393
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:667
Definition bslstl_map.h:619
BloombergLP::bslstl::TreeIterator< const value_type, Node, difference_type > const_iterator
Definition bslstl_map.h:724
BloombergLP::bslstl::TreeIterator< value_type, Node, difference_type > iterator
Definition bslstl_map.h:722
Definition bslstl_sharedptr.h:1830
Definition bslma_allocator.h:457
Definition bslmt_mutex.h:315
Definition bsls_timeinterval.h:301
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bbldc_basicisma30360.h:112
Definition balxml_encoderoptions.h:68
Definition bslma_usesbslmaallocator.h:343