1251881Speter/* 2251881Speter * cache.c: cache interface for Subversion 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter#include "cache.h" 25251881Speter 26251881Spetersvn_error_t * 27251881Spetersvn_cache__set_error_handler(svn_cache__t *cache, 28251881Speter svn_cache__error_handler_t handler, 29251881Speter void *baton, 30251881Speter apr_pool_t *scratch_pool) 31251881Speter{ 32251881Speter cache->error_handler = handler; 33251881Speter cache->error_baton = baton; 34251881Speter return SVN_NO_ERROR; 35251881Speter} 36251881Speter 37251881Spetersvn_boolean_t 38251881Spetersvn_cache__is_cachable(svn_cache__t *cache, 39251881Speter apr_size_t size) 40251881Speter{ 41251881Speter /* having no cache means we can't cache anything */ 42251881Speter if (cache == NULL) 43251881Speter return FALSE; 44251881Speter 45251881Speter return cache->vtable->is_cachable(cache->cache_internal, size); 46251881Speter} 47251881Speter 48251881Speter/* Give the error handler callback a chance to replace or ignore the 49251881Speter error. */ 50251881Speterstatic svn_error_t * 51251881Speterhandle_error(svn_cache__t *cache, 52251881Speter svn_error_t *err, 53251881Speter apr_pool_t *pool) 54251881Speter{ 55251881Speter if (err) 56251881Speter { 57251881Speter cache->failures++; 58251881Speter if (cache->error_handler) 59251881Speter err = (cache->error_handler)(err, cache->error_baton, pool); 60251881Speter } 61251881Speter 62251881Speter return err; 63251881Speter} 64251881Speter 65251881Speter 66251881Spetersvn_error_t * 67251881Spetersvn_cache__get(void **value_p, 68251881Speter svn_boolean_t *found, 69251881Speter svn_cache__t *cache, 70251881Speter const void *key, 71251881Speter apr_pool_t *result_pool) 72251881Speter{ 73251881Speter svn_error_t *err; 74251881Speter 75251881Speter /* In case any errors happen and are quelched, make sure we start 76251881Speter out with FOUND set to false. */ 77251881Speter *found = FALSE; 78251881Speter#ifdef SVN_DEBUG 79299742Sdim if (cache->pretend_empty) 80251881Speter return SVN_NO_ERROR; 81251881Speter#endif 82251881Speter 83251881Speter cache->reads++; 84251881Speter err = handle_error(cache, 85251881Speter (cache->vtable->get)(value_p, 86251881Speter found, 87251881Speter cache->cache_internal, 88251881Speter key, 89251881Speter result_pool), 90251881Speter result_pool); 91251881Speter 92251881Speter if (*found) 93251881Speter cache->hits++; 94251881Speter 95251881Speter return err; 96251881Speter} 97251881Speter 98251881Spetersvn_error_t * 99299742Sdimsvn_cache__has_key(svn_boolean_t *found, 100299742Sdim svn_cache__t *cache, 101299742Sdim const void *key, 102299742Sdim apr_pool_t *scratch_pool) 103299742Sdim{ 104299742Sdim *found = FALSE; 105299742Sdim#ifdef SVN_DEBUG 106299742Sdim if (cache->pretend_empty) 107299742Sdim return SVN_NO_ERROR; 108299742Sdim#endif 109299742Sdim 110299742Sdim return handle_error(cache, 111299742Sdim (cache->vtable->has_key)(found, 112299742Sdim cache->cache_internal, 113299742Sdim key, 114299742Sdim scratch_pool), 115299742Sdim scratch_pool); 116299742Sdim} 117299742Sdim 118299742Sdimsvn_error_t * 119251881Spetersvn_cache__set(svn_cache__t *cache, 120251881Speter const void *key, 121251881Speter void *value, 122251881Speter apr_pool_t *scratch_pool) 123251881Speter{ 124251881Speter cache->writes++; 125251881Speter return handle_error(cache, 126251881Speter (cache->vtable->set)(cache->cache_internal, 127251881Speter key, 128251881Speter value, 129251881Speter scratch_pool), 130251881Speter scratch_pool); 131251881Speter} 132251881Speter 133251881Speter 134251881Spetersvn_error_t * 135251881Spetersvn_cache__iter(svn_boolean_t *completed, 136251881Speter svn_cache__t *cache, 137251881Speter svn_iter_apr_hash_cb_t user_cb, 138251881Speter void *user_baton, 139251881Speter apr_pool_t *scratch_pool) 140251881Speter{ 141251881Speter#ifdef SVN_DEBUG 142299742Sdim if (cache->pretend_empty) 143251881Speter /* Pretend CACHE is empty. */ 144251881Speter return SVN_NO_ERROR; 145251881Speter#endif 146251881Speter 147251881Speter return (cache->vtable->iter)(completed, 148251881Speter cache->cache_internal, 149251881Speter user_cb, 150251881Speter user_baton, 151251881Speter scratch_pool); 152251881Speter} 153251881Speter 154251881Spetersvn_error_t * 155251881Spetersvn_cache__get_partial(void **value, 156251881Speter svn_boolean_t *found, 157251881Speter svn_cache__t *cache, 158251881Speter const void *key, 159251881Speter svn_cache__partial_getter_func_t func, 160251881Speter void *baton, 161251881Speter apr_pool_t *result_pool) 162251881Speter{ 163251881Speter svn_error_t *err; 164251881Speter 165251881Speter /* In case any errors happen and are quelched, make sure we start 166251881Speter out with FOUND set to false. */ 167251881Speter *found = FALSE; 168251881Speter#ifdef SVN_DEBUG 169299742Sdim if (cache->pretend_empty) 170251881Speter return SVN_NO_ERROR; 171251881Speter#endif 172251881Speter 173251881Speter cache->reads++; 174251881Speter err = handle_error(cache, 175251881Speter (cache->vtable->get_partial)(value, 176251881Speter found, 177251881Speter cache->cache_internal, 178251881Speter key, 179251881Speter func, 180251881Speter baton, 181251881Speter result_pool), 182251881Speter result_pool); 183251881Speter 184251881Speter if (*found) 185251881Speter cache->hits++; 186251881Speter 187251881Speter return err; 188251881Speter} 189251881Speter 190251881Spetersvn_error_t * 191251881Spetersvn_cache__set_partial(svn_cache__t *cache, 192251881Speter const void *key, 193251881Speter svn_cache__partial_setter_func_t func, 194251881Speter void *baton, 195251881Speter apr_pool_t *scratch_pool) 196251881Speter{ 197251881Speter cache->writes++; 198251881Speter return handle_error(cache, 199251881Speter (cache->vtable->set_partial)(cache->cache_internal, 200251881Speter key, 201251881Speter func, 202251881Speter baton, 203251881Speter scratch_pool), 204251881Speter scratch_pool); 205251881Speter} 206251881Speter 207251881Spetersvn_error_t * 208251881Spetersvn_cache__get_info(svn_cache__t *cache, 209251881Speter svn_cache__info_t *info, 210251881Speter svn_boolean_t reset, 211251881Speter apr_pool_t *result_pool) 212251881Speter{ 213251881Speter /* write general statistics */ 214251881Speter 215299742Sdim memset(info, 0, sizeof(*info)); 216251881Speter info->gets = cache->reads; 217251881Speter info->hits = cache->hits; 218251881Speter info->sets = cache->writes; 219251881Speter info->failures = cache->failures; 220251881Speter 221251881Speter /* Call the cache implementation for filling the blanks. 222251881Speter * It might also replace some of the general stats but 223251881Speter * this is currently not done. 224251881Speter */ 225251881Speter SVN_ERR((cache->vtable->get_info)(cache->cache_internal, 226251881Speter info, 227251881Speter reset, 228251881Speter result_pool)); 229251881Speter 230251881Speter /* reset statistics */ 231251881Speter 232251881Speter if (reset) 233251881Speter { 234251881Speter cache->reads = 0; 235251881Speter cache->hits = 0; 236251881Speter cache->writes = 0; 237251881Speter cache->failures = 0; 238251881Speter } 239251881Speter 240251881Speter return SVN_NO_ERROR; 241251881Speter} 242251881Speter 243251881Spetersvn_string_t * 244251881Spetersvn_cache__format_info(const svn_cache__info_t *info, 245299742Sdim svn_boolean_t access_only, 246251881Speter apr_pool_t *result_pool) 247251881Speter{ 248251881Speter enum { _1MB = 1024 * 1024 }; 249251881Speter 250251881Speter apr_uint64_t misses = info->gets - info->hits; 251251881Speter double hit_rate = (100.0 * (double)info->hits) 252251881Speter / (double)(info->gets ? info->gets : 1); 253251881Speter double write_rate = (100.0 * (double)info->sets) 254251881Speter / (double)(misses ? misses : 1); 255251881Speter double data_usage_rate = (100.0 * (double)info->used_size) 256251881Speter / (double)(info->data_size ? info->data_size : 1); 257251881Speter double data_entry_rate = (100.0 * (double)info->used_entries) 258251881Speter / (double)(info->total_entries ? info->total_entries : 1); 259251881Speter 260299742Sdim const char *histogram = ""; 261299742Sdim if (!access_only) 262299742Sdim { 263299742Sdim svn_stringbuf_t *text = svn_stringbuf_create_empty(result_pool); 264251881Speter 265299742Sdim int i; 266299742Sdim int count = sizeof(info->histogram) / sizeof(info->histogram[0]); 267299742Sdim for (i = count - 1; i >= 0; --i) 268299742Sdim if (info->histogram[i] > 0 || text->len > 0) 269299742Sdim text = svn_stringbuf_createf(result_pool, 270299742Sdim i == count - 1 271299742Sdim ? "%s%12" APR_UINT64_T_FMT 272299742Sdim " buckets with >%d entries\n" 273299742Sdim : "%s%12" APR_UINT64_T_FMT 274299742Sdim " buckets with %d entries\n", 275299742Sdim text->data, info->histogram[i], i); 276299742Sdim 277299742Sdim histogram = text->data; 278299742Sdim } 279299742Sdim 280299742Sdim return access_only 281299742Sdim ? svn_string_createf(result_pool, 282299742Sdim "%s\n" 283251881Speter "gets : %" APR_UINT64_T_FMT 284251881Speter ", %" APR_UINT64_T_FMT " hits (%5.2f%%)\n" 285251881Speter "sets : %" APR_UINT64_T_FMT 286299742Sdim " (%5.2f%% of misses)\n", 287299742Sdim info->id, 288299742Sdim info->gets, 289299742Sdim info->hits, hit_rate, 290299742Sdim info->sets, write_rate) 291299742Sdim : svn_string_createf(result_pool, 292299742Sdim 293299742Sdim "%s\n" 294299742Sdim "gets : %" APR_UINT64_T_FMT 295299742Sdim ", %" APR_UINT64_T_FMT " hits (%5.2f%%)\n" 296299742Sdim "sets : %" APR_UINT64_T_FMT 297251881Speter " (%5.2f%% of misses)\n" 298251881Speter "failures: %" APR_UINT64_T_FMT "\n" 299251881Speter "used : %" APR_UINT64_T_FMT " MB (%5.2f%%)" 300251881Speter " of %" APR_UINT64_T_FMT " MB data cache" 301251881Speter " / %" APR_UINT64_T_FMT " MB total cache memory\n" 302251881Speter " %" APR_UINT64_T_FMT " entries (%5.2f%%)" 303299742Sdim " of %" APR_UINT64_T_FMT " total\n%s", 304251881Speter 305251881Speter info->id, 306251881Speter 307251881Speter info->gets, 308251881Speter info->hits, hit_rate, 309251881Speter info->sets, write_rate, 310251881Speter info->failures, 311251881Speter 312251881Speter info->used_size / _1MB, data_usage_rate, 313251881Speter info->data_size / _1MB, 314251881Speter info->total_size / _1MB, 315251881Speter 316251881Speter info->used_entries, data_entry_rate, 317299742Sdim info->total_entries, 318299742Sdim histogram); 319251881Speter} 320