summaryrefslogtreecommitdiff
path: root/subversion/include/private/svn_cache.h
blob: 08d2f09cb6147d5bce74c3f5dec0cdea3d8bebf1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
/**
 * @copyright
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you under the Apache License, Version 2.0 (the
 *    "License"); you may not use this file except in compliance
 *    with the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing,
 *    software distributed under the License is distributed on an
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *    KIND, either express or implied.  See the License for the
 *    specific language governing permissions and limitations
 *    under the License.
 * ====================================================================
 * @endcopyright
 *
 * @file svn_cache.h
 * @brief In-memory cache implementation.
 */


#ifndef SVN_CACHE_H
#define SVN_CACHE_H

#include <apr_pools.h>
#include <apr_hash.h>

#include "svn_types.h"
#include "svn_error.h"
#include "svn_iter.h"
#include "svn_config.h"
#include "svn_string.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */



/**
 * @defgroup svn_cache__support In-memory caching
 * @{
 */

/**
 * A function type for deserializing an object @a *out from the string
 * @a data of length @a data_len into @a result_pool. It is legal and
 * generally suggested that the deserialization will be done in-place,
 * i.e. modify @a data directly and return it in @a *out.
 */
typedef svn_error_t *(*svn_cache__deserialize_func_t)(void **out,
                                                      void *data,
                                                      apr_size_t data_len,
                                                      apr_pool_t *result_pool);

/**
 * A function type for deserializing an object @a *out from the string
 * @a data of length @a data_len into @a result_pool. The extra information
 * @a baton passed into can be used to deserialize only a specific part or
 * sub-structure or to perform any other non-modifying operation that may
 * not require the whole structure to be processed.
 */
typedef svn_error_t *(*svn_cache__partial_getter_func_t)(void **out,
                                                         const void *data,
                                                         apr_size_t data_len,
                                                         void *baton,
                                                         apr_pool_t *result_pool);

/**
 * A function type for modifying an already deserialized in the @a *data
 * buffer of length @a *data_len. Additional information of the modification
 * to do will be provided in @a baton. The function may change the size of
 * data buffer and may re-allocate it if necessary. In that case, the new
 * values must be passed back in @a *data_len and @a *data, respectively.
 * Allocations will be done from @a result_pool.
 */
typedef svn_error_t *(*svn_cache__partial_setter_func_t)(void **data,
                                                         apr_size_t *data_len,
                                                         void *baton,
                                                         apr_pool_t *result_pool);

/**
 * A function type for serializing an object @a in into bytes.  The
 * function should allocate the serialized value in @a result_pool, set
 * @a *data to the serialized value, and set @a *data_len to its length.
 */
typedef svn_error_t *(*svn_cache__serialize_func_t)(void **data,
                                                    apr_size_t *data_len,
                                                    void *in,
                                                    apr_pool_t *result_pool);

/**
 * A function type for transforming or ignoring errors.  @a scratch_pool may
 * be used for temporary allocations.
 */
typedef svn_error_t *(*svn_cache__error_handler_t)(svn_error_t *err,
                                                   void *baton,
                                                   apr_pool_t *scratch_pool);

/**
 * A wrapper around apr_memcache_t, provided essentially so that the
 * Subversion public API doesn't depend on whether or not you have
 * access to the APR memcache libraries.
 */
typedef struct svn_memcache_t svn_memcache_t;

/**
 * An opaque structure representing a membuffer cache object.
 */
typedef struct svn_membuffer_t svn_membuffer_t;

/**
 * Opaque type for an in-memory cache.
 */
typedef struct svn_cache__t svn_cache__t;

/**
 * A structure containing typical statistics about a given cache instance.
 * Use svn_cache__get_info() to get this data. Note that not all types
 * of caches will be able to report complete and correct information.
 */
typedef struct svn_cache__info_t
{
  /** A string identifying the cache instance. Usually a copy of the @a id
   * or @a prefix parameter passed to the cache constructor.
   */
  const char* id;

  /** Number of getter calls (svn_cache__get() or svn_cache__get()).
   */
  apr_uint64_t gets;

  /** Number of getter calls that return data.
   */
  apr_uint64_t hits;

  /** Number of setter calls (svn_cache__set()).
   */
  apr_uint64_t sets;

  /** Number of function calls that returned an error.
   */
  apr_uint64_t failures;

  /** Size of the data currently stored in the cache.
   * May be 0 if that information is not available.
   */
  apr_uint64_t used_size;

  /** Amount of memory currently reserved for cached data.
   * Will be equal to @a used_size if no precise information is available.
   */
  apr_uint64_t data_size;

  /** Lower threshold of the total size of memory allocated to the cache and
   * its index as well as management structures. The actual memory allocated
   * by the cache may be larger.
   */
  apr_uint64_t total_size;

  /** Number of cache entries.
   * May be 0 if that information is not available.
   */
  apr_uint64_t used_entries;

  /** Maximum numbers of cache entries.
   * May be 0 if that information is not available.
   */
  apr_uint64_t total_entries;
} svn_cache__info_t;

/**
 * Creates a new cache in @a *cache_p.  This cache will use @a pool
 * for all of its storage needs.  The elements in the cache will be
 * indexed by keys of length @a klen, which may be APR_HASH_KEY_STRING
 * if they are strings.  Cached values will be copied in and out of
 * the cache using @a serialize_func and @a deserialize_func, respectively.
 *
 * If @a deserialize_func is NULL, then the data is returned as an
 * svn_stringbuf_t; if @a serialize_func is NULL, then the data is
 * assumed to be an svn_stringbuf_t.
 *
 * The cache stores up to @a pages * @a items_per_page items at a
 * time.  The exact cache invalidation strategy is not defined here,
 * but in general, a lower value for @a items_per_page means more
 * memory overhead for the same number of items, but a higher value
 * for @a items_per_page means more items are cleared at once.  Both
 * @a pages and @a items_per_page must be positive (though they both
 * may certainly be 1).
 *
 * If @a thread_safe is true, and APR is compiled with threads, all
 * accesses to the cache will be protected with a mutex. The @a id
 * is a purely user-visible information that will allow coders to
 * identify this cache instance in a #svn_cache__info_t struct.
 * It does not influence the behavior of the cache itself.
 *
 * Note that NULL is a legitimate value for cache entries (and
 * @a serialize_func will not be called on it).
 *
 * It is not safe for @a serialize_func nor @a deserialize_func to
 * interact with the cache itself.
 */
svn_error_t *
svn_cache__create_inprocess(svn_cache__t **cache_p,
                            svn_cache__serialize_func_t serialize_func,
                            svn_cache__deserialize_func_t deserialize_func,
                            apr_ssize_t klen,
                            apr_int64_t pages,
                            apr_int64_t items_per_page,
                            svn_boolean_t thread_safe,
                            const char *id,
                            apr_pool_t *pool);

/**
 * Creates a new cache in @a *cache_p, communicating to a memcached
 * process via @a memcache.  The elements in the cache will be indexed
 * by keys of length @a klen, which may be APR_HASH_KEY_STRING if they
 * are strings.  Values will be serialized for memcached using @a
 * serialize_func and deserialized using @a deserialize_func.  Because
 * the same memcached server may cache many different kinds of values,
 * @a prefix should be specified to differentiate this cache from
 * other caches.  @a *cache_p will be allocated in @a result_pool.
 *
 * If @a deserialize_func is NULL, then the data is returned as an
 * svn_stringbuf_t; if @a serialize_func is NULL, then the data is
 * assumed to be an svn_stringbuf_t.
 *
 * These caches are always thread safe.
 *
 * These caches do not support svn_cache__iter.
 *
 * If Subversion was not built with apr_memcache support, always
 * raises SVN_ERR_NO_APR_MEMCACHE.
 */
svn_error_t *
svn_cache__create_memcache(svn_cache__t **cache_p,
                           svn_memcache_t *memcache,
                           svn_cache__serialize_func_t serialize_func,
                           svn_cache__deserialize_func_t deserialize_func,
                           apr_ssize_t klen,
                           const char *prefix,
                           apr_pool_t *result_pool);

/**
 * Given @a config, returns an APR memcached interface in @a
 * *memcache_p allocated in @a result_pool if @a config contains entries in
 * the SVN_CACHE_CONFIG_CATEGORY_MEMCACHED_SERVERS section describing
 * memcached servers; otherwise, sets @a *memcache_p to NULL.
 *
 * If Subversion was not built with apr_memcache_support, then raises
 * SVN_ERR_NO_APR_MEMCACHE if and only if @a config is configured to
 * use memcache.
 */
svn_error_t *
svn_cache__make_memcache_from_config(svn_memcache_t **memcache_p,
                                     svn_config_t *config,
                                     apr_pool_t *result_pool);

/**
 * Creates a new membuffer cache object in @a *cache. It will contain
 * up to @a total_size bytes of data, using @a directory_size bytes
 * for index information and the remainder for serialized objects.
 *
 * Since each index entry is about 50 bytes long, 1 to 10 percent of
 * the @a total_size should be allocated to the @a directory_size,
 * depending on the average serialized object size. Higher percentages
 * will generally result in higher hit rates and reduced conflict
 * resolution overhead.
 *
 * The cache will be split into @a segment_count segments of equal size.
 * A higher number reduces lock contention but also limits the maximum
 * cachable item size.  If it is not a power of two, it will be rounded
 * down to next lower power of two. Also, there is an implementation
 * specific upper limit and the setting will be capped there automatically.
 * If the number is 0, a default will be derived from @a total_size.
 *
 * If access to the resulting cache object is guaranteed to be serialized,
 * @a thread_safe may be set to @c FALSE for maximum performance.
 *
 * There is no limit on the number of threads reading a given cache segment
 * concurrently.  Writes, however, need an exclusive lock on the respective
 * segment.  @a allow_blocking_writes controls contention is handled here.
 * If set to TRUE, writes will wait until the lock becomes available, i.e.
 * reads should be short.  If set to FALSE, write attempts will be ignored
 * (no data being written to the cache) if some reader or another writer
 * currently holds the segment lock.
 *
 * Allocations will be made in @a result_pool, in particular the data buffers.
 */
svn_error_t *
svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
                                  apr_size_t total_size,
                                  apr_size_t directory_size,
                                  apr_size_t segment_count,
                                  svn_boolean_t thread_safe,
                                  svn_boolean_t allow_blocking_writes,
                                  apr_pool_t *result_pool);

/**
 * Creates a new cache in @a *cache_p, storing the data in a potentially
 * shared @a membuffer object.  The elements in the cache will be indexed
 * by keys of length @a klen, which may be APR_HASH_KEY_STRING if they
 * are strings.  Values will be serialized for the memcache using @a
 * serialize_func and deserialized using @a deserialize_func.  Because
 * the same memcache object may cache many different kinds of values
 * form multiple caches, @a prefix should be specified to differentiate
 * this cache from other caches.  @a *cache_p will be allocated in @a result_pool.
 *
 * If @a deserialize_func is NULL, then the data is returned as an
 * svn_stringbuf_t; if @a serialize_func is NULL, then the data is
 * assumed to be an svn_stringbuf_t.
 *
 * If @a thread_safe is true, and APR is compiled with threads, all
 * accesses to the cache will be protected with a mutex, if the shared
 * @a memcache has also been created with thread_safe flag set.
 *
 * These caches do not support svn_cache__iter.
 */
svn_error_t *
svn_cache__create_membuffer_cache(svn_cache__t **cache_p,
                                  svn_membuffer_t *membuffer,
                                  svn_cache__serialize_func_t serialize,
                                  svn_cache__deserialize_func_t deserialize,
                                  apr_ssize_t klen,
                                  const char *prefix,
                                  svn_boolean_t thread_safe,
                                  apr_pool_t *result_pool);

/**
 * Sets @a handler to be @a cache's error handling routine.  If any
 * error is returned from a call to svn_cache__get or svn_cache__set, @a
 * handler will be called with @a baton and the error, and the
 * original function will return whatever error @a handler returns
 * instead (possibly SVN_NO_ERROR); @a handler will receive the pool
 * passed to the svn_cache_* function.  @a scratch_pool is used for temporary
 * allocations.
 */
svn_error_t *
svn_cache__set_error_handler(svn_cache__t *cache,
                             svn_cache__error_handler_t handler,
                             void *baton,
                             apr_pool_t *scratch_pool);

/**
 * Returns @c TRUE if the @a cache supports objects of the given @a size.
 * There is no guarantee, that svn_cache__set() will actually store the
 * respective object in that case. However, a @c FALSE return value indicates
 * that an attempt to cache the item will either fail or impair the overall
 * cache performance. @c FALSE will also be returned if @a cache is @c NULL.
 */
svn_boolean_t
svn_cache__is_cachable(svn_cache__t *cache,
                       apr_size_t size);

#define SVN_CACHE_CONFIG_CATEGORY_MEMCACHED_SERVERS "memcached-servers"

/**
 * Fetches a value indexed by @a key from @a cache into @a *value,
 * setting @a *found to TRUE iff it is in the cache and FALSE if it is
 * not found.  @a key may be NULL in which case @a *found will be
 * FALSE.  The value is copied into @a result_pool using the deserialize
 * function provided to the cache's constructor.
 */
svn_error_t *
svn_cache__get(void **value,
               svn_boolean_t *found,
               svn_cache__t *cache,
               const void *key,
               apr_pool_t *result_pool);

/**
 * Stores the value @a value under the key @a key in @a cache.  Uses @a
 * scratch_pool for temporary allocations.  The cache makes copies of
 * @a key and @a value if necessary (that is, @a key and @a value may
 * have shorter lifetimes than the cache).  @a key may be NULL in which
 * case the cache will remain unchanged.
 *
 * If there is already a value for @a key, this will replace it.  Bear
 * in mind that in some circumstances this may leak memory (that is,
 * the cache's copy of the previous value may not be immediately
 * cleared); it is only guaranteed to not leak for caches created with
 * @a items_per_page equal to 1.
 */
svn_error_t *
svn_cache__set(svn_cache__t *cache,
               const void *key,
               void *value,
               apr_pool_t *scratch_pool);

/**
 * Iterates over the elements currently in @a cache, calling @a func
 * for each one until there are no more elements or @a func returns an
 * error.  Uses @a scratch_pool for temporary allocations.
 *
 * If @a completed is not NULL, then on return - if @a func returns no
 * errors - @a *completed will be set to @c TRUE.
 *
 * If @a func returns an error other than @c SVN_ERR_ITER_BREAK, that
 * error is returned.  When @a func returns @c SVN_ERR_ITER_BREAK,
 * iteration is interrupted, but no error is returned and @a
 * *completed is set to @c FALSE.  (The error handler set by
 * svn_cache__set_error_handler is not used for svn_cache__iter.)
 *
 * It is not legal to perform any other cache operations on @a cache
 * inside @a func.
 *
 * svn_cache__iter is not supported by all cache implementations; see
 * the svn_cache__create_* function for details.
 */
svn_error_t *
svn_cache__iter(svn_boolean_t *completed,
                svn_cache__t *cache,
                svn_iter_apr_hash_cb_t func,
                void *baton,
                apr_pool_t *scratch_pool);

/**
 * Similar to svn_cache__get() but will call a specific de-serialization
 * function @a func. @a found will be set depending on whether the @a key
 * has been found. Even if that reports @c TRUE, @a value may still return
 * a @c NULL pointer depending on the logic inside @a func.  For a @a NULL
 * @a key, no data will be found.  @a value will be allocated in
 * @a result_pool.
 */
svn_error_t *
svn_cache__get_partial(void **value,
                       svn_boolean_t *found,
                       svn_cache__t *cache,
                       const void *key,
                       svn_cache__partial_getter_func_t func,
                       void *baton,
                       apr_pool_t *result_pool);

/**
 * Find the item identified by @a key in the @a cache. If it has been found,
 * call @a func for it and @a baton to potentially modify the data. Changed
 * data will be written back to the cache. If the item cannot be found,
 * or if @a key is NULL, @a func does not get called. @a scratch_pool is
 * used for temporary allocations.
 */
svn_error_t *
svn_cache__set_partial(svn_cache__t *cache,
                       const void *key,
                       svn_cache__partial_setter_func_t func,
                       void *baton,
                       apr_pool_t *scratch_pool);

/**
 * Collect all available usage statistics on the cache instance @a cache
 * and write the data into @a info. If @a reset has been set, access
 * counters will be reset right after copying the statistics info.
 * @a result_pool will be used for allocations.
 */
svn_error_t *
svn_cache__get_info(svn_cache__t *cache,
                    svn_cache__info_t *info,
                    svn_boolean_t reset,
                    apr_pool_t *result_pool);

/**
 * Return the information given in @a info formatted as a multi-line string.
 * Allocations take place in @a result_pool.
 */
svn_string_t *
svn_cache__format_info(const svn_cache__info_t *info,
                       apr_pool_t *result_pool);

/* Access the process-global (singleton) membuffer cache. The first call
 * will automatically allocate the cache using the current cache config.
 * NULL will be returned if the desired cache size is 0.
 *
 * @since New in 1.7.
 */
struct svn_membuffer_t *
svn_cache__get_global_membuffer_cache(void);

/** @} */


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* SVN_CACHE_H */