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} |