blncache.c revision 299742
1/*
2 * blncache.c: DAV baseline information cache.
3 *
4 * ====================================================================
5 *    Licensed to the Apache Software Foundation (ASF) under one
6 *    or more contributor license agreements.  See the NOTICE file
7 *    distributed with this work for additional information
8 *    regarding copyright ownership.  The ASF licenses this file
9 *    to you under the Apache License, Version 2.0 (the
10 *    "License"); you may not use this file except in compliance
11 *    with the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 *    Unless required by applicable law or agreed to in writing,
16 *    software distributed under the License is distributed on an
17 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 *    KIND, either express or implied.  See the License for the
19 *    specific language governing permissions and limitations
20 *    under the License.
21 * ====================================================================
22 */
23
24#include <apr_pools.h>
25
26#include "svn_hash.h"
27#include "svn_dirent_uri.h"
28#include "svn_types.h"
29#include "svn_pools.h"
30
31#include "blncache.h"
32
33/* Baseline information cache object. */
34typedef struct baseline_info_t
35{
36  const char *bc_url;    /* baseline collection URL. */
37  svn_revnum_t revision; /* revision associated with the baseline. */
38
39} baseline_info_t;
40
41/* Module-private structure used to hold the caches. */
42struct svn_ra_serf__blncache_t
43{
44  /* A hash mapping 'svn_revnum_t *' baseline revisions to 'const
45   * char *' baseline collection URLs.
46   */
47  apr_hash_t *revnum_to_bc;
48
49  /* A hash mapping 'const char *' baseline URLs to 'baseline_info_t *'
50   * structures. (Allocated from the same pool as 'revnum_to_bc'.)
51   */
52  apr_hash_t *baseline_info;
53};
54
55
56
57/* Return a pointer to an 'baseline_info_t' structure allocated from
58 * POOL and populated with BC_URL (which is duped into POOL) and
59 * REVISION.
60 */
61static baseline_info_t *
62baseline_info_make(const char *bc_url,
63                   svn_revnum_t revision,
64                   apr_pool_t *pool)
65{
66  baseline_info_t *result = apr_palloc(pool, sizeof(*result));
67
68  result->bc_url = apr_pstrdup(pool, bc_url);
69  result->revision = revision;
70
71  return result;
72}
73
74/* Set in HASH the value VAL for the KEY (whose key length is KLEN).
75 * KEY will be duped into HASH's pool.
76 */
77static void
78hash_set_copy(apr_hash_t *hash,
79              const void *key,
80              apr_ssize_t klen,
81              const void *val)
82{
83  if (klen == APR_HASH_KEY_STRING)
84    klen = strlen(key);
85  apr_hash_set(hash, apr_pmemdup(apr_hash_pool_get(hash), key, klen),
86               klen, val);
87}
88
89
90svn_error_t *
91svn_ra_serf__blncache_create(svn_ra_serf__blncache_t **blncache_p,
92                             apr_pool_t *pool)
93{
94  svn_ra_serf__blncache_t *blncache = apr_pcalloc(pool, sizeof(*blncache));
95  apr_pool_t *cache_pool;
96
97  /* Create subpool for cached data. It will be cleared if we reach maximum
98   * cache size.*/
99  cache_pool = svn_pool_create(pool);
100  blncache->revnum_to_bc = apr_hash_make(cache_pool);
101  blncache->baseline_info = apr_hash_make(cache_pool);
102
103  *blncache_p = blncache;
104
105  return SVN_NO_ERROR;
106}
107
108#define MAX_CACHE_SIZE 1000
109
110svn_error_t *
111svn_ra_serf__blncache_set(svn_ra_serf__blncache_t *blncache,
112                          const char *baseline_url,
113                          svn_revnum_t revision,
114                          const char *bc_url,
115                          apr_pool_t *scratch_pool)
116{
117  if (bc_url && SVN_IS_VALID_REVNUM(revision))
118    {
119      apr_pool_t *cache_pool = apr_hash_pool_get(blncache->revnum_to_bc);
120
121      /* If the caches are too big, delete and recreate 'em and move along. */
122      if (MAX_CACHE_SIZE < (apr_hash_count(blncache->baseline_info)
123                            + apr_hash_count(blncache->revnum_to_bc)))
124        {
125          svn_pool_clear(cache_pool);
126          blncache->revnum_to_bc = apr_hash_make(cache_pool);
127          blncache->baseline_info = apr_hash_make(cache_pool);
128        }
129
130      hash_set_copy(blncache->revnum_to_bc, &revision, sizeof(revision),
131                    apr_pstrdup(cache_pool, bc_url));
132
133      if (baseline_url)
134        {
135          hash_set_copy(blncache->baseline_info, baseline_url,
136                        APR_HASH_KEY_STRING,
137                        baseline_info_make(bc_url, revision, cache_pool));
138        }
139    }
140
141  return SVN_NO_ERROR;
142}
143
144#undef MAX_CACHE_SIZE
145
146svn_error_t *
147svn_ra_serf__blncache_get_bc_url(const char **bc_url_p,
148                                 svn_ra_serf__blncache_t *blncache,
149                                 svn_revnum_t revnum,
150                                 apr_pool_t *result_pool)
151{
152  const char *value = apr_hash_get(blncache->revnum_to_bc,
153                                   &revnum, sizeof(revnum));
154  *bc_url_p = value ? apr_pstrdup(result_pool, value) : NULL;
155  return SVN_NO_ERROR;
156}
157
158svn_error_t *
159svn_ra_serf__blncache_get_baseline_info(const char **bc_url_p,
160                                        svn_revnum_t *revision_p,
161                                        svn_ra_serf__blncache_t *blncache,
162                                        const char *baseline_url,
163                                        apr_pool_t *pool)
164{
165  baseline_info_t *info = svn_hash_gets(blncache->baseline_info, baseline_url);
166  if (info)
167    {
168      *bc_url_p = apr_pstrdup(pool, info->bc_url);
169      *revision_p = info->revision;
170    }
171  else
172    {
173      *bc_url_p = NULL;
174      *revision_p = SVN_INVALID_REVNUM;
175    }
176
177  return SVN_NO_ERROR;
178}
179
180