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 79251881Speter if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT")) 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 * 99251881Spetersvn_cache__set(svn_cache__t *cache, 100251881Speter const void *key, 101251881Speter void *value, 102251881Speter apr_pool_t *scratch_pool) 103251881Speter{ 104251881Speter cache->writes++; 105251881Speter return handle_error(cache, 106251881Speter (cache->vtable->set)(cache->cache_internal, 107251881Speter key, 108251881Speter value, 109251881Speter scratch_pool), 110251881Speter scratch_pool); 111251881Speter} 112251881Speter 113251881Speter 114251881Spetersvn_error_t * 115251881Spetersvn_cache__iter(svn_boolean_t *completed, 116251881Speter svn_cache__t *cache, 117251881Speter svn_iter_apr_hash_cb_t user_cb, 118251881Speter void *user_baton, 119251881Speter apr_pool_t *scratch_pool) 120251881Speter{ 121251881Speter#ifdef SVN_DEBUG 122251881Speter if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT")) 123251881Speter /* Pretend CACHE is empty. */ 124251881Speter return SVN_NO_ERROR; 125251881Speter#endif 126251881Speter 127251881Speter return (cache->vtable->iter)(completed, 128251881Speter cache->cache_internal, 129251881Speter user_cb, 130251881Speter user_baton, 131251881Speter scratch_pool); 132251881Speter} 133251881Speter 134251881Spetersvn_error_t * 135251881Spetersvn_cache__get_partial(void **value, 136251881Speter svn_boolean_t *found, 137251881Speter svn_cache__t *cache, 138251881Speter const void *key, 139251881Speter svn_cache__partial_getter_func_t func, 140251881Speter void *baton, 141251881Speter apr_pool_t *result_pool) 142251881Speter{ 143251881Speter svn_error_t *err; 144251881Speter 145251881Speter /* In case any errors happen and are quelched, make sure we start 146251881Speter out with FOUND set to false. */ 147251881Speter *found = FALSE; 148251881Speter#ifdef SVN_DEBUG 149251881Speter if (getenv("SVN_X_DOES_NOT_MARK_THE_SPOT")) 150251881Speter return SVN_NO_ERROR; 151251881Speter#endif 152251881Speter 153251881Speter cache->reads++; 154251881Speter err = handle_error(cache, 155251881Speter (cache->vtable->get_partial)(value, 156251881Speter found, 157251881Speter cache->cache_internal, 158251881Speter key, 159251881Speter func, 160251881Speter baton, 161251881Speter result_pool), 162251881Speter result_pool); 163251881Speter 164251881Speter if (*found) 165251881Speter cache->hits++; 166251881Speter 167251881Speter return err; 168251881Speter} 169251881Speter 170251881Spetersvn_error_t * 171251881Spetersvn_cache__set_partial(svn_cache__t *cache, 172251881Speter const void *key, 173251881Speter svn_cache__partial_setter_func_t func, 174251881Speter void *baton, 175251881Speter apr_pool_t *scratch_pool) 176251881Speter{ 177251881Speter cache->writes++; 178251881Speter return handle_error(cache, 179251881Speter (cache->vtable->set_partial)(cache->cache_internal, 180251881Speter key, 181251881Speter func, 182251881Speter baton, 183251881Speter scratch_pool), 184251881Speter scratch_pool); 185251881Speter} 186251881Speter 187251881Spetersvn_error_t * 188251881Spetersvn_cache__get_info(svn_cache__t *cache, 189251881Speter svn_cache__info_t *info, 190251881Speter svn_boolean_t reset, 191251881Speter apr_pool_t *result_pool) 192251881Speter{ 193251881Speter /* write general statistics */ 194251881Speter 195251881Speter info->gets = cache->reads; 196251881Speter info->hits = cache->hits; 197251881Speter info->sets = cache->writes; 198251881Speter info->failures = cache->failures; 199251881Speter 200251881Speter /* Call the cache implementation for filling the blanks. 201251881Speter * It might also replace some of the general stats but 202251881Speter * this is currently not done. 203251881Speter */ 204251881Speter SVN_ERR((cache->vtable->get_info)(cache->cache_internal, 205251881Speter info, 206251881Speter reset, 207251881Speter result_pool)); 208251881Speter 209251881Speter /* reset statistics */ 210251881Speter 211251881Speter if (reset) 212251881Speter { 213251881Speter cache->reads = 0; 214251881Speter cache->hits = 0; 215251881Speter cache->writes = 0; 216251881Speter cache->failures = 0; 217251881Speter } 218251881Speter 219251881Speter return SVN_NO_ERROR; 220251881Speter} 221251881Speter 222251881Spetersvn_string_t * 223251881Spetersvn_cache__format_info(const svn_cache__info_t *info, 224251881Speter apr_pool_t *result_pool) 225251881Speter{ 226251881Speter enum { _1MB = 1024 * 1024 }; 227251881Speter 228251881Speter apr_uint64_t misses = info->gets - info->hits; 229251881Speter double hit_rate = (100.0 * (double)info->hits) 230251881Speter / (double)(info->gets ? info->gets : 1); 231251881Speter double write_rate = (100.0 * (double)info->sets) 232251881Speter / (double)(misses ? misses : 1); 233251881Speter double data_usage_rate = (100.0 * (double)info->used_size) 234251881Speter / (double)(info->data_size ? info->data_size : 1); 235251881Speter double data_entry_rate = (100.0 * (double)info->used_entries) 236251881Speter / (double)(info->total_entries ? info->total_entries : 1); 237251881Speter 238251881Speter return svn_string_createf(result_pool, 239251881Speter 240251881Speter "prefix : %s\n" 241251881Speter "gets : %" APR_UINT64_T_FMT 242251881Speter ", %" APR_UINT64_T_FMT " hits (%5.2f%%)\n" 243251881Speter "sets : %" APR_UINT64_T_FMT 244251881Speter " (%5.2f%% of misses)\n" 245251881Speter "failures: %" APR_UINT64_T_FMT "\n" 246251881Speter "used : %" APR_UINT64_T_FMT " MB (%5.2f%%)" 247251881Speter " of %" APR_UINT64_T_FMT " MB data cache" 248251881Speter " / %" APR_UINT64_T_FMT " MB total cache memory\n" 249251881Speter " %" APR_UINT64_T_FMT " entries (%5.2f%%)" 250251881Speter " of %" APR_UINT64_T_FMT " total\n", 251251881Speter 252251881Speter info->id, 253251881Speter 254251881Speter info->gets, 255251881Speter info->hits, hit_rate, 256251881Speter info->sets, write_rate, 257251881Speter info->failures, 258251881Speter 259251881Speter info->used_size / _1MB, data_usage_rate, 260251881Speter info->data_size / _1MB, 261251881Speter info->total_size / _1MB, 262251881Speter 263251881Speter info->used_entries, data_entry_rate, 264251881Speter info->total_entries); 265251881Speter} 266