| 1 | /* |
| 2 | This file is part of the KDE project. |
| 3 | |
| 4 | SPDX-FileCopyrightText: 2010 Michael Pyne <mpyne@kde.org> |
| 5 | |
| 6 | SPDX-License-Identifier: LGPL-2.0-only |
| 7 | */ |
| 8 | |
| 9 | #ifndef KSHAREDDATACACHE_H |
| 10 | #define KSHAREDDATACACHE_H |
| 11 | |
| 12 | #include <kcoreaddons_export.h> |
| 13 | |
| 14 | class QString; |
| 15 | class QByteArray; |
| 16 | |
| 17 | /*! |
| 18 | * \class KSharedDataCache |
| 19 | * \inmodule KCoreAddons |
| 20 | * |
| 21 | * \brief A simple data cache which uses shared memory to quickly access data |
| 22 | * stored on disk. |
| 23 | * |
| 24 | * This class is meant to be used with KImageCache and similar classes but can |
| 25 | * be used directly if used with care. |
| 26 | * |
| 27 | * Example usage: |
| 28 | * |
| 29 | * \code |
| 30 | * QString loadTranslatedDocument(KSharedDataCache *cache) { |
| 31 | * |
| 32 | * // Find the data |
| 33 | * QByteArray document; |
| 34 | * |
| 35 | * if (!cache->find("translated-doc-template", &document)) { |
| 36 | * // Entry is not cached, manually generate and then add to cache. |
| 37 | * document = translateDocument(globalTemplate()); |
| 38 | * cache->insert(document); |
| 39 | * } |
| 40 | * |
| 41 | * // Don't forget to encode/decode properly |
| 42 | * return QString::fromUtf8(document); |
| 43 | * } |
| 44 | * \endcode |
| 45 | * |
| 46 | * \sa KImageCache |
| 47 | * \since 4.5 |
| 48 | */ |
| 49 | class KCOREADDONS_EXPORT KSharedDataCache |
| 50 | { |
| 51 | public: |
| 52 | /*! |
| 53 | * Attaches to a shared cache, creating it if necessary. If supported, this |
| 54 | * data cache will be shared across all processes using this cache (with |
| 55 | * subsequent memory savings). If shared memory is unsupported or a |
| 56 | * failure occurs, caching will still be supported, but only in the same |
| 57 | * process, and only using the same KSharedDataCache object. |
| 58 | * |
| 59 | * \a cacheName Name of the cache to use/share. |
| 60 | * |
| 61 | * \a defaultCacheSize Amount of data to be able to store, in bytes. The |
| 62 | * actual size will be slightly larger on disk due to accounting |
| 63 | * overhead. If the cache already existed then it will not be |
| 64 | * resized. For this reason you should specify some reasonable size. |
| 65 | * |
| 66 | * \a expectedItemSize The average size of an item that would be stored |
| 67 | * in the cache, in bytes. Choosing an average size of zero bytes causes |
| 68 | * KSharedDataCache to use whatever it feels is the best default for the |
| 69 | * system. |
| 70 | */ |
| 71 | KSharedDataCache(const QString &cacheName, unsigned defaultCacheSize, unsigned expectedItemSize = 0); |
| 72 | ~KSharedDataCache(); |
| 73 | |
| 74 | KSharedDataCache(const KSharedDataCache &) = delete; |
| 75 | KSharedDataCache &operator=(const KSharedDataCache &) = delete; |
| 76 | |
| 77 | /*! |
| 78 | * \value NoEvictionPreference No preference |
| 79 | * \value EvictLeastRecentlyUsed Evict the least recently used entry |
| 80 | * \value EvictLeastOftenUsed Evict the lest often used item |
| 81 | * \value EvictOldest Evict the oldest item |
| 82 | */ |
| 83 | enum EvictionPolicy { |
| 84 | // The default value for data in our shared memory will be 0, so it is |
| 85 | // important that whatever we want for the default value is also 0. |
| 86 | NoEvictionPreference = 0, |
| 87 | EvictLeastRecentlyUsed, |
| 88 | EvictLeastOftenUsed, |
| 89 | EvictOldest, |
| 90 | }; |
| 91 | |
| 92 | /*! |
| 93 | * Returns the removal policy in use by the shared cache. |
| 94 | */ |
| 95 | EvictionPolicy evictionPolicy() const; |
| 96 | |
| 97 | /*! |
| 98 | * Sets the entry removal policy for the shared cache to |
| 99 | * |
| 100 | * \a newPolicy. The default is EvictionPolicy::NoEvictionPreference. |
| 101 | */ |
| 102 | void setEvictionPolicy(EvictionPolicy newPolicy); |
| 103 | |
| 104 | /*! |
| 105 | * Attempts to insert the entry \a data into the shared cache, named by |
| 106 | * \a key, and returns true only if successful. |
| 107 | * |
| 108 | * Note that even if the insert was successful, that the newly added entry |
| 109 | * may be evicted by other processes contending for the cache. |
| 110 | */ |
| 111 | bool insert(const QString &key, const QByteArray &data); |
| 112 | |
| 113 | /*! |
| 114 | * Attempts to remove an entry with the specified \a key. Returns \c true if an entry has |
| 115 | * been removed; otherwise returns \c false. |
| 116 | * |
| 117 | * \since 6.18 |
| 118 | */ |
| 119 | bool remove(const QString &key); |
| 120 | |
| 121 | /*! |
| 122 | * Returns the data in the cache named by \a key (even if it's some other |
| 123 | * process's data named with the same key!), stored in \a destination. If there is |
| 124 | * no entry named by \a key then \a destination is left unchanged. The return value |
| 125 | * is used to tell what happened. |
| 126 | * |
| 127 | * If you simply want to verify whether an entry is present in the cache then |
| 128 | * see contains(). |
| 129 | * |
| 130 | * \a key The key to find in the cache. |
| 131 | * |
| 132 | * \a destination Is set to the value of \a key in the cache if \a key is |
| 133 | * present, left unchanged otherwise. |
| 134 | * |
| 135 | * Returns true if \a key was present in the cache (\a destination will also be |
| 136 | * updated), false if \a key was not present (\a destination will be |
| 137 | * unchanged). |
| 138 | */ |
| 139 | bool find(const QString &key, QByteArray *destination) const; |
| 140 | |
| 141 | /*! |
| 142 | * Removes all entries from the cache. |
| 143 | */ |
| 144 | void clear(); |
| 145 | |
| 146 | /*! |
| 147 | * Removes the underlying file from the cache. Note that this is *all* that this |
| 148 | * function does. The shared memory segment is still attached and will still contain |
| 149 | * all the data until all processes currently attached remove the mapping. |
| 150 | * |
| 151 | * In order to remove the data see clear(). |
| 152 | */ |
| 153 | static void deleteCache(const QString &cacheName); |
| 154 | |
| 155 | /*! |
| 156 | * Returns true if the cache currently contains the image for the given |
| 157 | * filename. |
| 158 | * |
| 159 | * \note Calling this function is threadsafe, but it is in general not |
| 160 | * possible to guarantee the image stays cached immediately afterwards, |
| 161 | * so if you need the result use find(). |
| 162 | */ |
| 163 | bool contains(const QString &key) const; |
| 164 | |
| 165 | /*! |
| 166 | * Returns the usable cache size in bytes. The actual amount of memory |
| 167 | * used will be slightly larger than this to account for required |
| 168 | * accounting overhead. |
| 169 | */ |
| 170 | unsigned totalSize() const; |
| 171 | |
| 172 | /*! |
| 173 | * Returns the amount of free space in the cache, in bytes. Due to |
| 174 | * implementation details it is possible to still not be able to fit an |
| 175 | * entry in the cache at any given time even if it is smaller than the |
| 176 | * amount of space remaining. |
| 177 | */ |
| 178 | unsigned freeSize() const; |
| 179 | |
| 180 | /*! |
| 181 | * Returns the shared timestamp of the cache. The interpretation of the |
| 182 | * timestamp returned is up to the application. KSharedDataCache |
| 183 | * will initialize the timestamp to the time returned by \c time(2) |
| 184 | * on cache creation, but KSharedDataCache will not touch the |
| 185 | * timestamp again. |
| 186 | * \sa setTimestamp() |
| 187 | * \since 4.6 |
| 188 | */ |
| 189 | unsigned timestamp() const; |
| 190 | |
| 191 | /*! |
| 192 | * Sets the shared timestamp of the cache. Timestamping is supported to |
| 193 | * allow applications to more effectively "version" the data stored in the |
| 194 | * cache. However, the timestamp is shared with all applications |
| 195 | * using the cache so you should always be prepared for invalid |
| 196 | * timestamps. |
| 197 | * |
| 198 | * When the cache is first created (note that this is different from |
| 199 | * attaching to an existing shared cache on disk), the cache timestamp is |
| 200 | * initialized to the time returned by \c time(2). KSharedDataCache will |
| 201 | * not update the timestamp again, it is only updated through this method. |
| 202 | * |
| 203 | * Example: |
| 204 | * \code |
| 205 | * QImage loadCachedImage(const QString &key) |
| 206 | * { |
| 207 | * // Check timestamp |
| 208 | * if (m_sharedCache->timestamp() < m_currentThemeTimestamp) { |
| 209 | * // Cache is stale, clean it out. |
| 210 | * m_sharedCache->clear(); |
| 211 | * m_sharedCache->setTimestamp(m_currentThemeTimestamp); |
| 212 | * } |
| 213 | * |
| 214 | * // Check cache and load image as usual... |
| 215 | * } |
| 216 | * \endcode |
| 217 | * |
| 218 | * \a newTimestamp The new timestamp to mark the shared cache with. |
| 219 | * \sa timestamp() |
| 220 | * \since 4.6 |
| 221 | */ |
| 222 | void setTimestamp(unsigned newTimestamp); |
| 223 | |
| 224 | private: |
| 225 | class Private; |
| 226 | Private *d; |
| 227 | }; |
| 228 | |
| 229 | #endif |
| 230 | |