File: cache.h

package info (click to toggle)
hercules 3.13-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,392 kB
  • sloc: ansic: 175,124; sh: 8,792; makefile: 760; perl: 149
file content (379 lines) | stat: -rw-r--r-- 17,448 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/* CACHE.H    (c)Copyright Greg Smith, 2002-2009                     */
/*            Buffer Cache Manager                                   */

/*-------------------------------------------------------------------
  Description:
    Manages multiple caches in a multi-threaded environment.  A cache
    is dynamically created and destroyed.  It's size or number of
    entries is also dynamically determined.  A cache entry contains
    an identifying `key', `flags' which indicate whether an entry is
    busy or not, and a `buf' which is a pointer to the cached object.

  Cache entry:
    The structure of a cache entry is:
      U64       key;
      U32       flag;
      int       len;
      void     *buf;
      int       value;
      U64       age;
    The first 8 bits of the flag indicates if the entry is `busy' or
    not.  If any of the first 8 bits are non-zero then the entry is
    considered `busy' and will not be stolen or otherwise reused.

  APIs:

    General query functions:
      int         cache_nbr(int ix); [0]
                  Number of entries

      int         cache_busy(int ix);
                  Number of busy entries

      int         cache_empty(int ix);
                  Number of empty entries [1]

      int         cache_waiters(int ix);
                  Number of waiters for a non-busy cache entry

      long long   cache_size(int ix);
                  Size of all allocated objects

      long long   cache_hits(int ix);
                  Number of successful lookups

      long long   cache_misses(int ix);
                  Number of unsuccessful lookups

      int         cache_busy_percent(int ix);
                  Percentage (0 .. 100) of entries that are busy

      int         cache_empty_percent(int ix);
                  Percentage of entries that are empty [1]

      int         cache_hit_percent(int ix);
                  Percentage of successful lookups to total lookups

     Notes        [0] `ix' identifies the cache.  This is an integer
                      and is reserved in `cache.h'
                  [1] An empty entry contains a zero key value.
                      A valid key should not be all zeroes
                      (0x0000000000000000) or all ones
                      (0xffffffffffffffff).   All ones is used to
                      indicate an error circumstance.

    Entry specific functions:
      U64         cache_getkey(int ix, int i); [0]
                  Return key for the specified cache entry

      U64         cache_setkey(int ix, int i, U64 key);
                  Set the key for the specified cache entry;
                  the old key is returned

      U32         cache_getflag(int ix, int i);
                  Return the flag for the specified cache entry

      U32         cache_setflag(int ix, int i, U32 andbits, U32 orbits);
                  Set the flag for the specified cache entry; first
                  the `andbits' value is `and'ed against the entry then
                  the `orbits' value is `or'ed against the entry.  The
                  old flag is returned.

      U64         cache_getage(int ix, int i); [1]
                  Return age for the specified cache entry

      U64         cache_setage(int ix, int i);
                  Set age for the specified cache entry

      void       *cache_getbuf(int ix, int i, int len);
                  Return address of the object buf for the cache entry.
                  If `len' is non-zero, then if the current object
                  is null or `len' is greater than the current object
                  length then the old object is freed and a new
                  object is obtained.

      void       *cache_setbuf(int ix, int i, void *buf, int len);
                  The old object address and length is replaced.
                  The address of the old object is returned and
                  can be freed using `free()'.

      int         cache_getlen(int ix, int i);
                  Return the length of the current object

       Notes      [0] `i' is the index of the entry in cache `ix'
                  [1] `age' is a sequentially incremented value and
                      does not correspond to date or time

    Locking functions:
      int         cache_lock(int ix);
                  Obtain the lock for cache `ix'.  If the cache does
                  not exist then it will be created.  Generally, the
                  lock should be obtained when referencing cache
                  entries and must be held when a cache entry status
                  may change from `busy' to `not busy' or vice versa.
                  Likewise, the lock must be held when a cache entry
                  changes from `empty' to `not empty' or vice versa.

      int         cache_unlock(int ix);
                  Release the cache lock

    Search functions:
      int         cache_lookup(int ix, U64 key, int *o);
                  Search cache `ix' for entry matching `key'.
                  If a non-NULL pointer `o' is provided, then the
                  oldest or preferred cache entry index is returned
                  that is available to be stolen.

      int         cache_scan (int ix, int (rtn)(), void *data);
                  Scan a cache routine entry by entry calling routine
                  `rtn'.  Parameters passed to the routine are
                  `(int *answer, int ix, int i, void *data)'  where
                  `ix' is the cache index, `i' is the cache entry
                  index and `data' is the value passed to cache_scan.
                  `*answer' is initialized to -1 and can be set by
                  the scan subroutine.  This will be the value returned
                  by cache_scan.  If the routine returns a non-zero
                  value then the scan is terminated.

    Other functions:
      int         cache_wait(int ix);
                  Wait for a non-busy cache entry to become available.
                  Typically called after `cache_lookup' was
                  unsuccessful and `*o' is -1.

      int         cache_release(int ix, int i, int flag);
                  Release the cache entry.  If flag is CACHE_FREEBUF
                  then the object buffer is also freed.

      int         cache_cmd(int argc, char *argv[], char *cmdline);
                  Interface with the cache command processor.  This
                  interface is subject to change.

  -------------------------------------------------------------------*/

#ifndef _HERCULES_CACHE_H
#define _HERCULES_CACHE_H 1

#include "hercules.h"


#ifndef _CACHE_C_
#ifndef _HDASD_DLL_
#define CCH_DLL_IMPORT DLL_IMPORT
#else   /* _HDASD_DLL_ */
#define CCH_DLL_IMPORT extern
#endif  /* _HDASD_DLL_ */
#else
#define CCH_DLL_IMPORT DLL_EXPORT
#endif

/*-------------------------------------------------------------------*/
/* Reserve cache indexes here                                        */
/*-------------------------------------------------------------------*/
#define  CACHE_MAX_INDEX              8 /* Max number caches [0..7]  */

#define  CACHE_DEVBUF                 0 /* Device Buffer cache       */
#define  CACHE_L2                     1 /* L2 cache                  */
#define  CACHE_2                      2 /*      (available)          */
#define  CACHE_3                      3 /*      (available)          */
#define  CACHE_4                      4 /*      (available)          */
#define  CACHE_5                      5 /*      (available)          */
#define  CACHE_6                      6 /*      (available)          */
#define  CACHE_7                      7 /*      (available)          */

#ifdef _CACHE_C_
/*-------------------------------------------------------------------*/
/* Cache entry                                                       */
/*-------------------------------------------------------------------*/
typedef struct _CACHE {                 /* Cache entry               */
      U64       key;                    /* Key                       */
      U32       flag;                   /* Flags                     */
      int       len;                    /* Buffer length             */
      void     *buf;                    /* Buffer address            */
      int       value;                  /* Arbitrary value           */
      U64       age;                    /* Age                       */
    } CACHE;

/*-------------------------------------------------------------------*/
/* Cache header                                                      */
/*-------------------------------------------------------------------*/
typedef struct _CACHEBLK {              /* Cache header              */
      int       magic;                  /* Magic number              */
      int       nbr;                    /* Number entries            */
      int       busy;                   /* Number busy entries       */
      int       empty;                  /* Number empty entries      */
      int       waiters;                /* Number waiters            */
      int       waits;                  /* Number times waited       */
      long long size;                   /* Allocated buffer size     */
      long long hits;                   /* Number lookup hits        */
      long long fasthits;               /* Number fast lookup hits   */
      long long misses;                 /* Number lookup misses      */
      U64       age;                    /* Age counter               */
      LOCK      lock;                   /* Lock                      */
      COND      waitcond;               /* Wait for available entry  */
      CACHE    *cache;                  /* Cache table address       */
      time_t    atime;                  /* Time last adjustment      */
      time_t    wtime;                  /* Time last wait            */
      int       adjusts;                /* Number of adjustments     */
    } CACHEBLK;
#endif

/*-------------------------------------------------------------------*/
/* Flag definitions                                                  */
/*-------------------------------------------------------------------*/
#define CACHE_BUSY           0xFF000000 /* Busy bits                 */
#define CACHE_TYPE           0x000000FF /* Type bits                 */

#define CACHE_FREEBUF                 1 /* Free buf on release       */

#ifdef _CACHE_C_
#define CACHE_MAGIC          0x01CACE10 /* Magic number              */
#define CACHE_DEFAULT_NBR           229 /* Initial entries (prime)   */
//FIXME the line below increases the size for CACHE_L2.  Since each
//      cckd device always has an active l2 entry this number
//      actually limits the number of cckd devices that can be
//      attached.
//      This is a workaround to increase the max number of devices
#define CACHE_DEFAULT_L2_NBR       1031 /* Initial entries for L2    */

#define CACHE_WAITTIME             1000 /* Wait time for entry(usec) */

#define CACHE_ADJUST_INTERVAL        15 /* Adjustment interval (sec) */
#define CACHE_ADJUST_NUMBER         128 /* Uninhibited nbr entries   */
#define CACHE_ADJUST_BUSY1           70 /* Increase when this busy 1 */
#define CACHE_ADJUST_BUSY2           80 /* Increase when this busy 2 */
#define CACHE_ADJUST_RESIZE           8 /* Nbr entries adjusted      */
#define CACHE_ADJUST_EMPTY           16 /* Decrease this many empty  */
#define CACHE_ADJUST_HIT1            60 /* Increase hit% this low  1 */
#define CACHE_ADJUST_HIT2            50 /* Increase hit% this low  2 */
#define CACHE_ADJUST_BUSY3           20 /* Decrease not this busy    */
#define CACHE_ADJUST_HIT3            90 /*      and hit% this high   */
#define CACHE_ADJUST_SIZE  (8*1024*1024)/*      and size this high   */
#define CACHE_ADJUST_WAITTIME        10 /* Increase last wait  (sec) */
#endif

/*-------------------------------------------------------------------*/
/* Functions                                                         */
/*-------------------------------------------------------------------*/
int         cache_nbr(int ix);
int         cache_busy(int ix);
int         cache_empty(int ix);
int         cache_waiters(int ix);
long long   cache_size(int ix);
long long   cache_hits(int ix);
long long   cache_misses(int ix);
int         cache_busy_percent(int ix);
int         cache_empty_percent(int ix);
int         cache_hit_percent(int ix);
int         cache_lookup(int ix, U64 key, int *o);
typedef int CACHE_SCAN_RTN (int *answer, int ix, int i, void *data);
int         cache_scan (int ix, CACHE_SCAN_RTN rtn, void *data);
int         cache_lock(int ix);
int         cache_unlock(int ix);
int         cache_wait(int ix);
U64         cache_getkey(int ix, int i);
U64         cache_setkey(int ix, int i, U64 key);
U32         cache_getflag(int ix, int i);
U32         cache_setflag(int ix, int i, U32 andbits, U32 orbits);
U64         cache_getage(int ix, int i);
U64         cache_setage(int ix, int i);
void       *cache_getbuf(int ix, int i, int len);
void       *cache_setbuf(int ix, int i, void *buf, int len);
int         cache_getlen(int ix, int i);
int         cache_getval(int ix, int i);
int         cache_setval(int ix, int i, int val);
int         cache_release(int ix, int i, int flag);
CCH_DLL_IMPORT int         cache_cmd(int argc, char *argv[], char *cmdline);

#ifdef _CACHE_C_
static int  cache_create (int ix);
static int  cache_destroy (int ix);
static int  cache_check_ix(int ix);
static int  cache_check_cache(int ix);
static int  cache_check(int ix, int i);
static int  cache_isbusy(int ix, int i);
static int  cache_isempty(int ix, int i);
static int  cache_adjust(int ix, int n);
#if 0
static int  cache_resize (int ix, int n);
#endif
static void cache_allocbuf(int ix, int i, int len);
#endif

/*-------------------------------------------------------------------*/
/* Specific cache definitions (until a better place is found)        */
/*-------------------------------------------------------------------*/

/*-------------------------------------------------------------------*/
/* Device buffer definitions                                         */
/*-------------------------------------------------------------------*/
#define   CCKD_CACHE_ACTIVE  0x80000000 /* Active entry              */
#define   CCKD_CACHE_READING 0x40000000 /* Entry being read          */
#define   CCKD_CACHE_WRITING 0x20000000 /* Entry being written       */
#define   CCKD_CACHE_IOBUSY  (CCKD_CACHE_READING|CCKD_CACHE_WRITING)
#define   CCKD_CACHE_IOWAIT  0x10000000 /* Waiters for i/o           */
#define   CCKD_CACHE_UPDATED 0x08000000 /* Buffer has been updated   */
#define   CCKD_CACHE_WRITE   0x04000000 /* Entry pending write       */
#define   CCKD_CACHE_USED    0x00800000 /* Entry has been used       */

#define   CKD_CACHE_ACTIVE   0x80000000 /* Active entry              */
#define   FBA_CACHE_ACTIVE   0x80000000 /* Active entry              */
#define   SHRD_CACHE_ACTIVE  0x80000000 /* Active entry              */

#define   DEVBUF_TYPE_SHARED 0x00000080 /* Shared entry type         */
#define   DEVBUF_TYPE_COMP   0x00000040 /* CCKD/CFBA entry type      */
#define   DEVBUF_TYPE_CKD    0x00000002 /* CKD entry type            */
#define   DEVBUF_TYPE_FBA    0x00000001 /* FBA entry type            */

#define   DEVBUF_TYPE_CCKD    (DEVBUF_TYPE_COMP|DEVBUF_TYPE_CKD)
#define   DEVBUF_TYPE_CFBA    (DEVBUF_TYPE_COMP|DEVBUF_TYPE_FBA)
#define   DEVBUF_TYPE_SCKD    (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_CKD)
#define   DEVBUF_TYPE_SFBA    (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_FBA)

#define CCKD_CACHE_GETKEY(_ix, _devnum, _trk) \
do { \
  (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \
  (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \
} while (0)
#define CCKD_CACHE_SETKEY(_devnum, _trk) \
  ((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))

#define CKD_CACHE_GETKEY(_ix, _devnum, _trk) \
{ \
  (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \
  (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \
}
#define CKD_CACHE_SETKEY(_devnum, _trk) \
  ((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))

#define FBA_CACHE_GETKEY(_ix, _devnum, _blkgrp) \
{ \
  (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \
  (_blkgrp) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \
}
#define FBA_CACHE_SETKEY(_devnum, _blkgrp) \
  ((U64)(((U64)(_devnum) << 32) | (U64)(_blkgrp)))

#define SHRD_CACHE_GETKEY(_ix, _devnum, _trk) \
{ \
  (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \
  (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \
}
#define SHRD_CACHE_SETKEY(_devnum, _trk) \
  ((U64)(((U64)(_devnum) << 32) | (U64)(_trk)))

/*-------------------------------------------------------------------*/
/* L2 definitions                                                    */
/*-------------------------------------------------------------------*/
#define   L2_CACHE_ACTIVE    0x80000000 /* Active entry              */

#define L2_CACHE_GETKEY(_ix, _sfx, _devnum, _trk) \
do { \
  (_sfx) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 48) & 0xFFFF); \
  (_devnum) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 32) & 0xFFFF); \
  (_trk) = (U32)(cache_getkey(CACHE_L2,(_ix)) & 0xFFFFFFFF); \
} while (0)
#define L2_CACHE_SETKEY(_sfx, _devnum, _trk) \
  ((U64)(((U64)(_sfx) << 48) | ((U64)(_devnum) << 32) | (U64)(_trk)))

#endif /* _HERCULES_CACHE_H */