1 /* CACHE.H (c)Copyright Greg Smith, 2002-2009 */ 2 /* Buffer Cache Manager */ 3 4 /*------------------------------------------------------------------- 5 Description: 6 Manages multiple caches in a multi-threaded environment. A cache 7 is dynamically created and destroyed. It's size or number of 8 entries is also dynamically determined. A cache entry contains 9 an identifying `key', `flags' which indicate whether an entry is 10 busy or not, and a `buf' which is a pointer to the cached object. 11 12 Cache entry: 13 The structure of a cache entry is: 14 U64 key; 15 U32 flag; 16 int len; 17 void *buf; 18 int value; 19 U64 age; 20 The first 8 bits of the flag indicates if the entry is `busy' or 21 not. If any of the first 8 bits are non-zero then the entry is 22 considered `busy' and will not be stolen or otherwise reused. 23 24 APIs: 25 26 General query functions: 27 int cache_nbr(int ix); [0] 28 Number of entries 29 30 int cache_busy(int ix); 31 Number of busy entries 32 33 int cache_empty(int ix); 34 Number of empty entries [1] 35 36 int cache_waiters(int ix); 37 Number of waiters for a non-busy cache entry 38 39 long long cache_size(int ix); 40 Size of all allocated objects 41 42 long long cache_hits(int ix); 43 Number of successful lookups 44 45 long long cache_misses(int ix); 46 Number of unsuccessful lookups 47 48 int cache_busy_percent(int ix); 49 Percentage (0 .. 100) of entries that are busy 50 51 int cache_empty_percent(int ix); 52 Percentage of entries that are empty [1] 53 54 int cache_hit_percent(int ix); 55 Percentage of successful lookups to total lookups 56 57 Notes [0] `ix' identifies the cache. This is an integer 58 and is reserved in `cache.h' 59 [1] An empty entry contains a zero key value. 60 A valid key should not be all zeroes 61 (0x0000000000000000) or all ones 62 (0xffffffffffffffff). All ones is used to 63 indicate an error circumstance. 64 65 Entry specific functions: 66 U64 cache_getkey(int ix, int i); [0] 67 Return key for the specified cache entry 68 69 U64 cache_setkey(int ix, int i, U64 key); 70 Set the key for the specified cache entry; 71 the old key is returned 72 73 U32 cache_getflag(int ix, int i); 74 Return the flag for the specified cache entry 75 76 U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits); 77 Set the flag for the specified cache entry; first 78 the `andbits' value is `and'ed against the entry then 79 the `orbits' value is `or'ed against the entry. The 80 old flag is returned. 81 82 U64 cache_getage(int ix, int i); [1] 83 Return age for the specified cache entry 84 85 U64 cache_setage(int ix, int i); 86 Set age for the specified cache entry 87 88 void *cache_getbuf(int ix, int i, int len); 89 Return address of the object buf for the cache entry. 90 If `len' is non-zero, then if the current object 91 is null or `len' is greater than the current object 92 length then the old object is freed and a new 93 object is obtained. 94 95 void *cache_setbuf(int ix, int i, void *buf, int len); 96 The old object address and length is replaced. 97 The address of the old object is returned and 98 can be freed using `free()'. 99 100 int cache_getlen(int ix, int i); 101 Return the length of the current object 102 103 Notes [0] `i' is the index of the entry in cache `ix' 104 [1] `age' is a sequentially incremented value and 105 does not correspond to date or time 106 107 Locking functions: 108 int cache_lock(int ix); 109 Obtain the lock for cache `ix'. If the cache does 110 not exist then it will be created. Generally, the 111 lock should be obtained when referencing cache 112 entries and must be held when a cache entry status 113 may change from `busy' to `not busy' or vice versa. 114 Likewise, the lock must be held when a cache entry 115 changes from `empty' to `not empty' or vice versa. 116 117 int cache_unlock(int ix); 118 Release the cache lock 119 120 Search functions: 121 int cache_lookup(int ix, U64 key, int *o); 122 Search cache `ix' for entry matching `key'. 123 If a non-NULL pointer `o' is provided, then the 124 oldest or preferred cache entry index is returned 125 that is available to be stolen. 126 127 int cache_scan (int ix, int (rtn)(), void *data); 128 Scan a cache routine entry by entry calling routine 129 `rtn'. Parameters passed to the routine are 130 `(int *answer, int ix, int i, void *data)' where 131 `ix' is the cache index, `i' is the cache entry 132 index and `data' is the value passed to cache_scan. 133 `*answer' is initialized to -1 and can be set by 134 the scan subroutine. This will be the value returned 135 by cache_scan. If the routine returns a non-zero 136 value then the scan is terminated. 137 138 Other functions: 139 int cache_wait(int ix); 140 Wait for a non-busy cache entry to become available. 141 Typically called after `cache_lookup' was 142 unsuccessful and `*o' is -1. 143 144 int cache_release(int ix, int i, int flag); 145 Release the cache entry. If flag is CACHE_FREEBUF 146 then the object buffer is also freed. 147 148 int cache_cmd(int argc, char *argv[], char *cmdline); 149 Interface with the cache command processor. This 150 interface is subject to change. 151 152 -------------------------------------------------------------------*/ 153 154 #ifndef _HERCULES_CACHE_H 155 #define _HERCULES_CACHE_H 1 156 157 #include "hercules.h" 158 159 160 #ifndef _CACHE_C_ 161 #ifndef _HDASD_DLL_ 162 #define CCH_DLL_IMPORT DLL_IMPORT 163 #else /* _HDASD_DLL_ */ 164 #define CCH_DLL_IMPORT extern 165 #endif /* _HDASD_DLL_ */ 166 #else 167 #define CCH_DLL_IMPORT DLL_EXPORT 168 #endif 169 170 /*-------------------------------------------------------------------*/ 171 /* Reserve cache indexes here */ 172 /*-------------------------------------------------------------------*/ 173 #define CACHE_MAX_INDEX 8 /* Max number caches [0..7] */ 174 175 #define CACHE_DEVBUF 0 /* Device Buffer cache */ 176 #define CACHE_L2 1 /* L2 cache */ 177 #define CACHE_2 2 /* (available) */ 178 #define CACHE_3 3 /* (available) */ 179 #define CACHE_4 4 /* (available) */ 180 #define CACHE_5 5 /* (available) */ 181 #define CACHE_6 6 /* (available) */ 182 #define CACHE_7 7 /* (available) */ 183 184 #ifdef _CACHE_C_ 185 /*-------------------------------------------------------------------*/ 186 /* Cache entry */ 187 /*-------------------------------------------------------------------*/ 188 typedef struct _CACHE { /* Cache entry */ 189 U64 key; /* Key */ 190 U32 flag; /* Flags */ 191 int len; /* Buffer length */ 192 void *buf; /* Buffer address */ 193 int value; /* Arbitrary value */ 194 U64 age; /* Age */ 195 } CACHE; 196 197 /*-------------------------------------------------------------------*/ 198 /* Cache header */ 199 /*-------------------------------------------------------------------*/ 200 typedef struct _CACHEBLK { /* Cache header */ 201 int magic; /* Magic number */ 202 int nbr; /* Number entries */ 203 int busy; /* Number busy entries */ 204 int empty; /* Number empty entries */ 205 int waiters; /* Number waiters */ 206 int waits; /* Number times waited */ 207 long long size; /* Allocated buffer size */ 208 long long hits; /* Number lookup hits */ 209 long long fasthits; /* Number fast lookup hits */ 210 long long misses; /* Number lookup misses */ 211 U64 age; /* Age counter */ 212 LOCK lock; /* Lock */ 213 COND waitcond; /* Wait for available entry */ 214 CACHE *cache; /* Cache table address */ 215 time_t atime; /* Time last adjustment */ 216 time_t wtime; /* Time last wait */ 217 int adjusts; /* Number of adjustments */ 218 } CACHEBLK; 219 #endif 220 221 /*-------------------------------------------------------------------*/ 222 /* Flag definitions */ 223 /*-------------------------------------------------------------------*/ 224 #define CACHE_BUSY 0xFF000000 /* Busy bits */ 225 #define CACHE_TYPE 0x000000FF /* Type bits */ 226 227 #define CACHE_FREEBUF 1 /* Free buf on release */ 228 229 #ifdef _CACHE_C_ 230 #define CACHE_MAGIC 0x01CACE10 /* Magic number */ 231 #define CACHE_DEFAULT_NBR 229 /* Initial entries (prime) */ 232 //FIXME the line below increases the size for CACHE_L2. Since each 233 // cckd device always has an active l2 entry this number 234 // actually limits the number of cckd devices that can be 235 // attached. 236 // This is a workaround to increase the max number of devices 237 #define CACHE_DEFAULT_L2_NBR 1031 /* Initial entries for L2 */ 238 239 #define CACHE_WAITTIME 1000 /* Wait time for entry(usec) */ 240 241 #define CACHE_ADJUST_INTERVAL 15 /* Adjustment interval (sec) */ 242 #define CACHE_ADJUST_NUMBER 128 /* Uninhibited nbr entries */ 243 #define CACHE_ADJUST_BUSY1 70 /* Increase when this busy 1 */ 244 #define CACHE_ADJUST_BUSY2 80 /* Increase when this busy 2 */ 245 #define CACHE_ADJUST_RESIZE 8 /* Nbr entries adjusted */ 246 #define CACHE_ADJUST_EMPTY 16 /* Decrease this many empty */ 247 #define CACHE_ADJUST_HIT1 60 /* Increase hit% this low 1 */ 248 #define CACHE_ADJUST_HIT2 50 /* Increase hit% this low 2 */ 249 #define CACHE_ADJUST_BUSY3 20 /* Decrease not this busy */ 250 #define CACHE_ADJUST_HIT3 90 /* and hit% this high */ 251 #define CACHE_ADJUST_SIZE (8*1024*1024)/* and size this high */ 252 #define CACHE_ADJUST_WAITTIME 10 /* Increase last wait (sec) */ 253 #endif 254 255 /*-------------------------------------------------------------------*/ 256 /* Functions */ 257 /*-------------------------------------------------------------------*/ 258 int cache_nbr(int ix); 259 int cache_busy(int ix); 260 int cache_empty(int ix); 261 int cache_waiters(int ix); 262 long long cache_size(int ix); 263 long long cache_hits(int ix); 264 long long cache_misses(int ix); 265 int cache_busy_percent(int ix); 266 int cache_empty_percent(int ix); 267 int cache_hit_percent(int ix); 268 int cache_lookup(int ix, U64 key, int *o); 269 typedef int CACHE_SCAN_RTN (int *answer, int ix, int i, void *data); 270 int cache_scan (int ix, CACHE_SCAN_RTN rtn, void *data); 271 int cache_lock(int ix); 272 int cache_unlock(int ix); 273 int cache_wait(int ix); 274 U64 cache_getkey(int ix, int i); 275 U64 cache_setkey(int ix, int i, U64 key); 276 U32 cache_getflag(int ix, int i); 277 U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits); 278 U64 cache_getage(int ix, int i); 279 U64 cache_setage(int ix, int i); 280 void *cache_getbuf(int ix, int i, int len); 281 void *cache_setbuf(int ix, int i, void *buf, int len); 282 int cache_getlen(int ix, int i); 283 int cache_getval(int ix, int i); 284 int cache_setval(int ix, int i, int val); 285 int cache_release(int ix, int i, int flag); 286 CCH_DLL_IMPORT int cache_cmd(int argc, char *argv[], char *cmdline); 287 288 #ifdef _CACHE_C_ 289 static int cache_create (int ix); 290 static int cache_destroy (int ix); 291 static int cache_check_ix(int ix); 292 static int cache_check_cache(int ix); 293 static int cache_check(int ix, int i); 294 static int cache_isbusy(int ix, int i); 295 static int cache_isempty(int ix, int i); 296 static int cache_adjust(int ix, int n); 297 #if 0 298 static int cache_resize (int ix, int n); 299 #endif 300 static void cache_allocbuf(int ix, int i, int len); 301 #endif 302 303 /*-------------------------------------------------------------------*/ 304 /* Specific cache definitions (until a better place is found) */ 305 /*-------------------------------------------------------------------*/ 306 307 /*-------------------------------------------------------------------*/ 308 /* Device buffer definitions */ 309 /*-------------------------------------------------------------------*/ 310 #define CCKD_CACHE_ACTIVE 0x80000000 /* Active entry */ 311 #define CCKD_CACHE_READING 0x40000000 /* Entry being read */ 312 #define CCKD_CACHE_WRITING 0x20000000 /* Entry being written */ 313 #define CCKD_CACHE_IOBUSY (CCKD_CACHE_READING|CCKD_CACHE_WRITING) 314 #define CCKD_CACHE_IOWAIT 0x10000000 /* Waiters for i/o */ 315 #define CCKD_CACHE_UPDATED 0x08000000 /* Buffer has been updated */ 316 #define CCKD_CACHE_WRITE 0x04000000 /* Entry pending write */ 317 #define CCKD_CACHE_USED 0x00800000 /* Entry has been used */ 318 319 #define CKD_CACHE_ACTIVE 0x80000000 /* Active entry */ 320 #define FBA_CACHE_ACTIVE 0x80000000 /* Active entry */ 321 #define SHRD_CACHE_ACTIVE 0x80000000 /* Active entry */ 322 323 #define DEVBUF_TYPE_SHARED 0x00000080 /* Shared entry type */ 324 #define DEVBUF_TYPE_COMP 0x00000040 /* CCKD/CFBA entry type */ 325 #define DEVBUF_TYPE_CKD 0x00000002 /* CKD entry type */ 326 #define DEVBUF_TYPE_FBA 0x00000001 /* FBA entry type */ 327 328 #define DEVBUF_TYPE_CCKD (DEVBUF_TYPE_COMP|DEVBUF_TYPE_CKD) 329 #define DEVBUF_TYPE_CFBA (DEVBUF_TYPE_COMP|DEVBUF_TYPE_FBA) 330 #define DEVBUF_TYPE_SCKD (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_CKD) 331 #define DEVBUF_TYPE_SFBA (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_FBA) 332 333 #define CCKD_CACHE_GETKEY(_ix, _devnum, _trk) \ 334 do { \ 335 (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ 336 (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ 337 } while (0) 338 #define CCKD_CACHE_SETKEY(_devnum, _trk) \ 339 ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) 340 341 #define CKD_CACHE_GETKEY(_ix, _devnum, _trk) \ 342 { \ 343 (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ 344 (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ 345 } 346 #define CKD_CACHE_SETKEY(_devnum, _trk) \ 347 ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) 348 349 #define FBA_CACHE_GETKEY(_ix, _devnum, _blkgrp) \ 350 { \ 351 (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ 352 (_blkgrp) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ 353 } 354 #define FBA_CACHE_SETKEY(_devnum, _blkgrp) \ 355 ((U64)(((U64)(_devnum) << 32) | (U64)(_blkgrp))) 356 357 #define SHRD_CACHE_GETKEY(_ix, _devnum, _trk) \ 358 { \ 359 (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ 360 (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ 361 } 362 #define SHRD_CACHE_SETKEY(_devnum, _trk) \ 363 ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) 364 365 /*-------------------------------------------------------------------*/ 366 /* L2 definitions */ 367 /*-------------------------------------------------------------------*/ 368 #define L2_CACHE_ACTIVE 0x80000000 /* Active entry */ 369 370 #define L2_CACHE_GETKEY(_ix, _sfx, _devnum, _trk) \ 371 do { \ 372 (_sfx) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 48) & 0xFFFF); \ 373 (_devnum) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 32) & 0xFFFF); \ 374 (_trk) = (U32)(cache_getkey(CACHE_L2,(_ix)) & 0xFFFFFFFF); \ 375 } while (0) 376 #define L2_CACHE_SETKEY(_sfx, _devnum, _trk) \ 377 ((U64)(((U64)(_sfx) << 48) | ((U64)(_devnum) << 32) | (U64)(_trk))) 378 379 #endif /* _HERCULES_CACHE_H */ 380