Deleted Added
full compact
object_pool.c (302408) object_pool.c (362181)
1/*
1/*
2 * config_pool.c : pool of configuration objects
2 * object_pool.c : generic pool of reference-counted objects
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

--- 33 unchanged lines hidden (view full) ---

44 /* reference to the parent container */
45 svn_object_pool__t *object_pool;
46
47 /* identifies the bucket in OBJECT_POOL->OBJECTS in which this entry
48 * belongs. */
49 svn_membuf_t key;
50
51 /* User provided object. Usually a wrapper. */
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

--- 33 unchanged lines hidden (view full) ---

44 /* reference to the parent container */
45 svn_object_pool__t *object_pool;
46
47 /* identifies the bucket in OBJECT_POOL->OBJECTS in which this entry
48 * belongs. */
49 svn_membuf_t key;
50
51 /* User provided object. Usually a wrapper. */
52 void *wrapper;
52 void *object;
53
54 /* private pool. This instance and its other members got allocated in it.
55 * Will be destroyed when this instance is cleaned up. */
56 apr_pool_t *pool;
57
58 /* Number of references to this data struct */
59 volatile svn_atomic_t ref_count;
60} object_ref_t;

--- 19 unchanged lines hidden (view full) ---

80
81 /* Number of entries in OBJECTS with a reference count 0.
82 Due to races, this may be *temporarily* off by one or more.
83 Hence we must not strictly depend on it. */
84 volatile svn_atomic_t unused_count;
85
86 /* the root pool owning this structure */
87 apr_pool_t *pool;
53
54 /* private pool. This instance and its other members got allocated in it.
55 * Will be destroyed when this instance is cleaned up. */
56 apr_pool_t *pool;
57
58 /* Number of references to this data struct */
59 volatile svn_atomic_t ref_count;
60} object_ref_t;

--- 19 unchanged lines hidden (view full) ---

80
81 /* Number of entries in OBJECTS with a reference count 0.
82 Due to races, this may be *temporarily* off by one or more.
83 Hence we must not strictly depend on it. */
84 volatile svn_atomic_t unused_count;
85
86 /* the root pool owning this structure */
87 apr_pool_t *pool;
88
89 /* extractor and updater for the user object wrappers */
90 svn_object_pool__getter_t getter;
91 svn_object_pool__setter_t setter;
92};
93
94
95/* Pool cleanup function for the whole object pool.
96 */
97static apr_status_t
98object_pool_cleanup(void *baton)
99{

--- 71 unchanged lines hidden (view full) ---

171add_object_ref(object_ref_t *object_ref,
172 apr_pool_t *pool)
173{
174 /* Update ref counter.
175 Note that this is racy with object_ref_cleanup; see comment there. */
176 if (svn_atomic_inc(&object_ref->ref_count) == 0)
177 svn_atomic_dec(&object_ref->object_pool->unused_count);
178
88};
89
90
91/* Pool cleanup function for the whole object pool.
92 */
93static apr_status_t
94object_pool_cleanup(void *baton)
95{

--- 71 unchanged lines hidden (view full) ---

167add_object_ref(object_ref_t *object_ref,
168 apr_pool_t *pool)
169{
170 /* Update ref counter.
171 Note that this is racy with object_ref_cleanup; see comment there. */
172 if (svn_atomic_inc(&object_ref->ref_count) == 0)
173 svn_atomic_dec(&object_ref->object_pool->unused_count);
174
179 /* make sure the reference gets released automatically */
180 apr_pool_cleanup_register(pool, object_ref, object_ref_cleanup,
181 apr_pool_cleanup_null);
175 /* Make sure the reference gets released automatically.
176 Since POOL might be a parent pool of OBJECT_REF->OBJECT_POOL,
177 to the reference counting update before destroing any of the
178 pool hierarchy. */
179 apr_pool_pre_cleanup_register(pool, object_ref, object_ref_cleanup);
182}
183
184/* Actual implementation of svn_object_pool__lookup.
185 *
186 * Requires external serialization on OBJECT_POOL.
187 */
188static svn_error_t *
189lookup(void **object,
190 svn_object_pool__t *object_pool,
191 svn_membuf_t *key,
180}
181
182/* Actual implementation of svn_object_pool__lookup.
183 *
184 * Requires external serialization on OBJECT_POOL.
185 */
186static svn_error_t *
187lookup(void **object,
188 svn_object_pool__t *object_pool,
189 svn_membuf_t *key,
192 void *baton,
193 apr_pool_t *result_pool)
194{
195 object_ref_t *object_ref
196 = apr_hash_get(object_pool->objects, key->data, key->size);
197
198 if (object_ref)
199 {
190 apr_pool_t *result_pool)
191{
192 object_ref_t *object_ref
193 = apr_hash_get(object_pool->objects, key->data, key->size);
194
195 if (object_ref)
196 {
200 *object = object_pool->getter(object_ref->wrapper, baton, result_pool);
197 *object = object_ref->object;
201 add_object_ref(object_ref, result_pool);
202 }
203 else
204 {
205 *object = NULL;
206 }
207
208 return SVN_NO_ERROR;
209}
210
211/* Actual implementation of svn_object_pool__insert.
212 *
213 * Requires external serialization on OBJECT_POOL.
214 */
215static svn_error_t *
216insert(void **object,
217 svn_object_pool__t *object_pool,
218 const svn_membuf_t *key,
198 add_object_ref(object_ref, result_pool);
199 }
200 else
201 {
202 *object = NULL;
203 }
204
205 return SVN_NO_ERROR;
206}
207
208/* Actual implementation of svn_object_pool__insert.
209 *
210 * Requires external serialization on OBJECT_POOL.
211 */
212static svn_error_t *
213insert(void **object,
214 svn_object_pool__t *object_pool,
215 const svn_membuf_t *key,
219 void *wrapper,
220 void *baton,
221 apr_pool_t *wrapper_pool,
216 void *item,
217 apr_pool_t *item_pool,
222 apr_pool_t *result_pool)
223{
224 object_ref_t *object_ref
225 = apr_hash_get(object_pool->objects, key->data, key->size);
226 if (object_ref)
227 {
218 apr_pool_t *result_pool)
219{
220 object_ref_t *object_ref
221 = apr_hash_get(object_pool->objects, key->data, key->size);
222 if (object_ref)
223 {
228 /* entry already exists (e.g. race condition) */
229 svn_error_t *err = object_pool->setter(&object_ref->wrapper,
230 wrapper, baton,
231 object_ref->pool);
232 if (err)
233 {
234 /* if we had an issue in the setter, then OBJECT_REF is in an
235 * unknown state now. Keep it around for the current users
236 * (i.e. don't clean the pool) but remove it from the list of
237 * available ones.
238 */
239 apr_hash_set(object_pool->objects, key->data, key->size, NULL);
240 svn_atomic_dec(&object_pool->object_count);
241
242 /* for the unlikely case that the object got created _and_
243 * already released since we last checked: */
244 if (svn_atomic_read(&object_ref->ref_count) == 0)
245 svn_atomic_dec(&object_pool->unused_count);
246
247 /* cleanup the new data as well because it's not safe to use
248 * either.
249 */
250 svn_pool_destroy(wrapper_pool);
251
252 /* propagate error */
253 return svn_error_trace(err);
254 }
255
256 /* Destroy the new one and return a reference to the existing one
257 * because the existing one may already have references on it.
258 */
224 /* Destroy the new one and return a reference to the existing one
225 * because the existing one may already have references on it.
226 */
259 svn_pool_destroy(wrapper_pool);
227 svn_pool_destroy(item_pool);
260 }
261 else
262 {
263 /* add new index entry */
228 }
229 else
230 {
231 /* add new index entry */
264 object_ref = apr_pcalloc(wrapper_pool, sizeof(*object_ref));
232 object_ref = apr_pcalloc(item_pool, sizeof(*object_ref));
265 object_ref->object_pool = object_pool;
233 object_ref->object_pool = object_pool;
266 object_ref->wrapper = wrapper;
267 object_ref->pool = wrapper_pool;
234 object_ref->object = item;
235 object_ref->pool = item_pool;
268
236
269 svn_membuf__create(&object_ref->key, key->size, wrapper_pool);
237 svn_membuf__create(&object_ref->key, key->size, item_pool);
270 object_ref->key.size = key->size;
271 memcpy(object_ref->key.data, key->data, key->size);
272
273 apr_hash_set(object_pool->objects, object_ref->key.data,
274 object_ref->key.size, object_ref);
275 svn_atomic_inc(&object_pool->object_count);
276
277 /* the new entry is *not* in use yet.
278 * add_object_ref will update counters again.
279 */
280 svn_atomic_inc(&object_ref->object_pool->unused_count);
281 }
282
283 /* return a reference to the object we just added */
238 object_ref->key.size = key->size;
239 memcpy(object_ref->key.data, key->data, key->size);
240
241 apr_hash_set(object_pool->objects, object_ref->key.data,
242 object_ref->key.size, object_ref);
243 svn_atomic_inc(&object_pool->object_count);
244
245 /* the new entry is *not* in use yet.
246 * add_object_ref will update counters again.
247 */
248 svn_atomic_inc(&object_ref->object_pool->unused_count);
249 }
250
251 /* return a reference to the object we just added */
284 *object = object_pool->getter(object_ref->wrapper, baton, result_pool);
252 *object = object_ref->object;
285 add_object_ref(object_ref, result_pool);
286
287 /* limit memory usage */
288 if (svn_atomic_read(&object_pool->unused_count) * 2
289 > apr_hash_count(object_pool->objects) + 2)
290 remove_unused_objects(object_pool);
291
292 return SVN_NO_ERROR;
293}
294
253 add_object_ref(object_ref, result_pool);
254
255 /* limit memory usage */
256 if (svn_atomic_read(&object_pool->unused_count) * 2
257 > apr_hash_count(object_pool->objects) + 2)
258 remove_unused_objects(object_pool);
259
260 return SVN_NO_ERROR;
261}
262
295/* Implement svn_object_pool__getter_t as no-op.
296 */
297static void *
298default_getter(void *object,
299 void *baton,
300 apr_pool_t *pool)
301{
302 return object;
303}
304
263
305/* Implement svn_object_pool__setter_t as no-op.
306 */
307static svn_error_t *
308default_setter(void **target,
309 void *source,
310 void *baton,
311 apr_pool_t *pool)
312{
313 return SVN_NO_ERROR;
314}
315
316
317/* API implementation */
318
319svn_error_t *
320svn_object_pool__create(svn_object_pool__t **object_pool,
264/* API implementation */
265
266svn_error_t *
267svn_object_pool__create(svn_object_pool__t **object_pool,
321 svn_object_pool__getter_t getter,
322 svn_object_pool__setter_t setter,
323 svn_boolean_t thread_safe,
324 apr_pool_t *pool)
325{
326 svn_object_pool__t *result;
327
328 /* construct the object pool in our private ROOT_POOL to survive POOL
329 * cleanup and to prevent threading issues with the allocator
330 */
331 result = apr_pcalloc(pool, sizeof(*result));
332 SVN_ERR(svn_mutex__init(&result->mutex, thread_safe, pool));
333
334 result->pool = pool;
335 result->objects = svn_hash__make(result->pool);
268 svn_boolean_t thread_safe,
269 apr_pool_t *pool)
270{
271 svn_object_pool__t *result;
272
273 /* construct the object pool in our private ROOT_POOL to survive POOL
274 * cleanup and to prevent threading issues with the allocator
275 */
276 result = apr_pcalloc(pool, sizeof(*result));
277 SVN_ERR(svn_mutex__init(&result->mutex, thread_safe, pool));
278
279 result->pool = pool;
280 result->objects = svn_hash__make(result->pool);
336 result->getter = getter ? getter : default_getter;
337 result->setter = setter ? setter : default_setter;
338
339 /* make sure we clean up nicely.
340 * We need two cleanup functions of which exactly one will be run
341 * (disabling the respective other as the first step). If the owning
342 * pool does not cleaned up / destroyed explicitly, it may live longer
343 * than our allocator. So, we need do act upon cleanup requests from
344 * either side - owning_pool and root_pool.
345 */
346 apr_pool_cleanup_register(pool, result, object_pool_cleanup,
347 apr_pool_cleanup_null);
348
349 *object_pool = result;
350 return SVN_NO_ERROR;
351}
352
353apr_pool_t *
281
282 /* make sure we clean up nicely.
283 * We need two cleanup functions of which exactly one will be run
284 * (disabling the respective other as the first step). If the owning
285 * pool does not cleaned up / destroyed explicitly, it may live longer
286 * than our allocator. So, we need do act upon cleanup requests from
287 * either side - owning_pool and root_pool.
288 */
289 apr_pool_cleanup_register(pool, result, object_pool_cleanup,
290 apr_pool_cleanup_null);
291
292 *object_pool = result;
293 return SVN_NO_ERROR;
294}
295
296apr_pool_t *
354svn_object_pool__new_wrapper_pool(svn_object_pool__t *object_pool)
297svn_object_pool__new_item_pool(svn_object_pool__t *object_pool)
355{
356 return svn_pool_create(object_pool->pool);
357}
358
298{
299 return svn_pool_create(object_pool->pool);
300}
301
359svn_mutex__t *
360svn_object_pool__mutex(svn_object_pool__t *object_pool)
361{
362 return object_pool->mutex;
363}
364
365unsigned
366svn_object_pool__count(svn_object_pool__t *object_pool)
367{
368 return svn_atomic_read(&object_pool->object_count);
369}
370
371svn_error_t *
372svn_object_pool__lookup(void **object,
373 svn_object_pool__t *object_pool,
374 svn_membuf_t *key,
302svn_error_t *
303svn_object_pool__lookup(void **object,
304 svn_object_pool__t *object_pool,
305 svn_membuf_t *key,
375 void *baton,
376 apr_pool_t *result_pool)
377{
378 *object = NULL;
379 SVN_MUTEX__WITH_LOCK(object_pool->mutex,
306 apr_pool_t *result_pool)
307{
308 *object = NULL;
309 SVN_MUTEX__WITH_LOCK(object_pool->mutex,
380 lookup(object, object_pool, key, baton, result_pool));
310 lookup(object, object_pool, key, result_pool));
381 return SVN_NO_ERROR;
382}
383
384svn_error_t *
385svn_object_pool__insert(void **object,
386 svn_object_pool__t *object_pool,
387 const svn_membuf_t *key,
311 return SVN_NO_ERROR;
312}
313
314svn_error_t *
315svn_object_pool__insert(void **object,
316 svn_object_pool__t *object_pool,
317 const svn_membuf_t *key,
388 void *wrapper,
389 void *baton,
390 apr_pool_t *wrapper_pool,
318 void *item,
319 apr_pool_t *item_pool,
391 apr_pool_t *result_pool)
392{
393 *object = NULL;
394 SVN_MUTEX__WITH_LOCK(object_pool->mutex,
320 apr_pool_t *result_pool)
321{
322 *object = NULL;
323 SVN_MUTEX__WITH_LOCK(object_pool->mutex,
395 insert(object, object_pool, key, wrapper, baton,
396 wrapper_pool, result_pool));
324 insert(object, object_pool, key, item,
325 item_pool, result_pool));
397 return SVN_NO_ERROR;
398}
326 return SVN_NO_ERROR;
327}