H5Cpkg.h

00001 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00002  * Copyright by The HDF Group.                                               *
00003  * Copyright by the Board of Trustees of the University of Illinois.         *
00004  * All rights reserved.                                                      *
00005  *                                                                           *
00006  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
00007  * terms governing use, modification, and redistribution, is contained in    *
00008  * the files COPYING and Copyright.html.  COPYING can be found at the root   *
00009  * of the source code distribution tree; Copyright.html can be found at the  *
00010  * root level of an installed copy of the electronic HDF5 document set and   *
00011  * is linked from the top-level documents page.  It can also be found at     *
00012  * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
00013  * access to either file, you may request a copy from help@hdfgroup.org.     *
00014  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00015 
00016 /*
00017  * Programmer: John Mainzer -- 10/12/04
00018  *
00019  * Purpose:     This file contains declarations which are normally visible
00020  *              only within the H5C package (just H5C.c at present).
00021  *
00022  *              Source files outside the H5C package should include
00023  *              H5Cprivate.h instead.
00024  *
00025  *              The one exception to this rule is test/cache.c.  The test
00026  *              code is easier to write if it can look at the cache's
00027  *              internal data structures.  Indeed, this is the main
00028  *              reason why this file was created.
00029  */
00030 
00031 #ifndef H5C_PACKAGE
00032 #error "Do not include this file outside the H5C package!"
00033 #endif
00034 
00035 #ifndef _H5Cpkg_H
00036 #define _H5Cpkg_H
00037 
00038 
00039 /* Get package's private header */
00040 #include "H5Cprivate.h"
00041 
00042 
00043 /* Get needed headers */
00044 #include "H5SLprivate.h"        /* Skip lists */
00045 
00046 /* With the introduction of the fractal heap, it is now possible for
00047  * entries to be dirtied, resized, and/or renamed in the flush callbacks.
00048  * As a result, on flushes, it may be necessary to make multiple passes
00049  * through the slist before it is empty.  The H5C__MAX_PASSES_ON_FLUSH
00050  * #define is used to set an upper limit on the number of passes.
00051  * The current value was obtained via personal communication with
00052  * Quincey.  I have applied a fudge factor of 2.
00053  */
00054 
00055 #define H5C__MAX_PASSES_ON_FLUSH        4
00056 
00057 
00058 
00059 /****************************************************************************
00060  *
00061  * structure H5C_t
00062  *
00063  * Catchall structure for all variables specific to an instance of the cache.
00064  *
00065  * While the individual fields of the structure are discussed below, the
00066  * following overview may be helpful.
00067  *
00068  * Entries in the cache are stored in an instance of H5TB_TREE, indexed on
00069  * the entry's disk address.  While the H5TB_TREE is less efficient than
00070  * hash table, it keeps the entries in address sorted order.  As flushes
00071  * in parallel mode are more efficient if they are issued in increasing
00072  * address order, this is a significant benefit.  Also the H5TB_TREE code
00073  * was readily available, which reduced development time.
00074  *
00075  * While the cache was designed with multiple replacement policies in mind,
00076  * at present only a modified form of LRU is supported.
00077  *
00078  *                                              JRM - 4/26/04
00079  *
00080  * Profiling has indicated that searches in the instance of H5TB_TREE are
00081  * too expensive.  To deal with this issue, I have augmented the cache
00082  * with a hash table in which all entries will be stored.  Given the
00083  * advantages of flushing entries in increasing address order, the TBBT
00084  * is retained, but only dirty entries are stored in it.  At least for
00085  * now, we will leave entries in the TBBT after they are flushed.
00086  *
00087  * Note that index_size and index_len now refer to the total size of
00088  * and number of entries in the hash table.
00089  *
00090  *                                              JRM - 7/19/04
00091  *
00092  * The TBBT has since been replaced with a skip list.  This change
00093  * greatly predates this note.
00094  *
00095  *                                              JRM - 9/26/05
00096  *
00097  * magic:       Unsigned 32 bit integer always set to H5C__H5C_T_MAGIC.  This
00098  *              field is used to validate pointers to instances of H5C_t.
00099  *
00100  * flush_in_progress: Boolean flag indicating whether a flush is in
00101  *              progress.
00102  *
00103  * trace_file_ptr:  File pointer pointing to the trace file, which is used
00104  *              to record cache operations for use in simulations and design
00105  *              studies.  This field will usually be NULL, indicating that
00106  *              no trace file should be recorded.
00107  *
00108  *              Since much of the code supporting the parallel metadata
00109  *              cache is in H5AC, we don't write the trace file from
00110  *              H5C.  Instead, H5AC reads the trace_file_ptr as needed.
00111  *
00112  *              When we get to using H5C in other places, we may add
00113  *              code to write trace file data at the H5C level as well.
00114  *
00115  * aux_ptr:     Pointer to void used to allow wrapper code to associate
00116  *              its data with an instance of H5C_t.  The H5C cache code
00117  *              sets this field to NULL, and otherwise leaves it alone.
00118  *
00119  * max_type_id: Integer field containing the maximum type id number assigned
00120  *              to a type of entry in the cache.  All type ids from 0 to
00121  *              max_type_id inclusive must be defined.  The names of the
00122  *              types are stored in the type_name_table discussed below, and
00123  *              indexed by the ids.
00124  *
00125  * type_name_table_ptr: Pointer to an array of pointer to char of length
00126  *              max_type_id + 1.  The strings pointed to by the entries
00127  *              in the array are the names of the entry types associated
00128  *              with the indexing type IDs.
00129  *
00130  * max_cache_size:  Nominal maximum number of bytes that may be stored in the
00131  *              cache.  This value should be viewed as a soft limit, as the
00132  *              cache can exceed this value under the following circumstances:
00133  *
00134  *              a) All entries in the cache are protected, and the cache is
00135  *                 asked to insert a new entry.  In this case the new entry
00136  *                 will be created.  If this causes the cache to exceed
00137  *                 max_cache_size, it will do so.  The cache will attempt
00138  *                 to reduce its size as entries are unprotected.
00139  *
00140  *              b) When running in parallel mode, the cache may not be
00141  *                 permitted to flush a dirty entry in response to a read.
00142  *                 If there are no clean entries available to evict, the
00143  *                 cache will exceed its maximum size.  Again the cache
00144  *                 will attempt to reduce its size to the max_cache_size
00145  *                 limit on the next cache write.
00146  *
00147  *              c) When an entry increases in size, the cache may exceed
00148  *                 the max_cache_size limit until the next time the cache
00149  *                 attempts to load or insert an entry.
00150  *
00151  * min_clean_size: Nominal minimum number of clean bytes in the cache.
00152  *              The cache attempts to maintain this number of bytes of
00153  *              clean data so as to avoid case b) above.  Again, this is
00154  *              a soft limit.
00155  *
00156  *
00157  * In addition to the call back functions required for each entry, the
00158  * cache requires the following call back functions for this instance of
00159  * the cache as a whole:
00160  *
00161  * check_write_permitted:  In certain applications, the cache may not
00162  *              be allowed to write to disk at certain time.  If specified,
00163  *              the check_write_permitted function is used to determine if
00164  *              a write is permissible at any given point in time.
00165  *
00166  *              If no such function is specified (i.e. this field is NULL),
00167  *              the cache uses the following write_permitted field to
00168  *              determine whether writes are permitted.
00169  *
00170  * write_permitted: If check_write_permitted is NULL, this boolean flag
00171  *              indicates whether writes are permitted.
00172  *
00173  * log_flush:   If provided, this function is called whenever a dirty
00174  *              entry is flushed to disk.
00175  *
00176  *
00177  * In cases where memory is plentiful, and performance is an issue, it
00178  * is useful to disable all cache evictions, and thereby postpone metadata
00179  * writes.  The following field is used to implement this.
00180  *
00181  * evictions_enabled:  Boolean flag that is initialized to TRUE.  When
00182  *              this flag is set to FALSE, the metadata cache will not
00183  *              attempt to evict entries to make space for newly protected
00184  *              entries, and instead the will grow without limit.
00185  *
00186  *              Needless to say, this feature must be used with care.
00187  *
00188  *
00189  * The cache requires an index to facilitate searching for entries.  The
00190  * following fields support that index.
00191  *
00192  * index_len:   Number of entries currently in the hash table used to index
00193  *              the cache.
00194  *
00195  * index_size:  Number of bytes of cache entries currently stored in the
00196  *              hash table used to index the cache.
00197  *
00198  *              This value should not be mistaken for footprint of the
00199  *              cache in memory.  The average cache entry is small, and
00200  *              the cache has a considerable overhead.  Multiplying the
00201  *              index_size by two should yield a conservative estimate
00202  *              of the cache's memory footprint.
00203  *
00204  * clean_index_size: Number of bytes of clean entries currently stored in
00205  *              the hash table.  Note that the index_size field (above)
00206  *              is also the sum of the sizes of all entries in the cache.
00207  *              Thus we should have the invarient that clean_index_size +
00208  *              dirty_index_size == index_size.
00209  *
00210  *              WARNING:
00211  *
00212  *              1) The clean_index_size field is not maintained by the
00213  *                 index macros, as the hash table doesn't care whether
00214  *                 the entry is clean or dirty.  Instead the field is
00215  *                 maintained in the H5C__UPDATE_RP macros.
00216  *
00217  *              2) The value of the clean_index_size must not be mistaken
00218  *                 for the current clean size of the cache.  Rather, the
00219  *                 clean size of the cache is the current value of
00220  *                 clean_index_size plus the amount of empty space (if any)
00221  *                 in the cache.
00222  *
00223  * dirty_index_size: Number of bytes of dirty entries currently stored in
00224  *              the hash table.  Note that the index_size field (above)
00225  *              is also the sum of the sizes of all entries in the cache.
00226  *              Thus we should have the invarient that clean_index_size +
00227  *              dirty_index_size == index_size.
00228  *
00229  *              WARNING:
00230  *
00231  *              1) The dirty_index_size field is not maintained by the
00232  *                 index macros, as the hash table doesn't care whether
00233  *                 the entry is clean or dirty.  Instead the field is
00234  *                 maintained in the H5C__UPDATE_RP macros.
00235  *
00236  * index:       Array of pointer to H5C_cache_entry_t of size
00237  *              H5C__HASH_TABLE_LEN.  At present, this value is a power
00238  *              of two, not the usual prime number.
00239  *
00240  *              I hope that the variable size of cache elements, the large
00241  *              hash table size, and the way in which HDF5 allocates space
00242  *              will combine to avoid problems with periodicity.  If so, we
00243  *              can use a trivial hash function (a bit-and and a 3 bit left
00244  *              shift) with some small savings.
00245  *
00246  *              If not, it will become evident in the statistics. Changing
00247  *              to the usual prime number length hash table will require
00248  *              changing the H5C__HASH_FCN macro and the deletion of the
00249  *              H5C__HASH_MASK #define.  No other changes should be required.
00250  *
00251  *
00252  * When we flush the cache, we need to write entries out in increasing
00253  * address order.  An instance of a skip list is used to store dirty entries in
00254  * sorted order.  Whether it is cheaper to sort the dirty entries as needed,
00255  * or to maintain the list is an open question.  At a guess, it depends
00256  * on how frequently the cache is flushed.  We will see how it goes.
00257  *
00258  * For now at least, I will not remove dirty entries from the list as they
00259  * are flushed. (this has been changed -- dirty entries are now removed from
00260  * the skip list as they are flushed.  JRM - 10/25/05)
00261  *
00262  * slist_len:   Number of entries currently in the skip list
00263  *              used to maintain a sorted list of dirty entries in the
00264  *              cache.
00265  *
00266  * slist_size:  Number of bytes of cache entries currently stored in the
00267  *              skip list used to maintain a sorted list of
00268  *              dirty entries in the cache.
00269  *
00270  * slist_ptr:   pointer to the instance of H5SL_t used maintain a sorted
00271  *              list of dirty entries in the cache.  This sorted list has
00272  *              two uses:
00273  *
00274  *              a) It allows us to flush dirty entries in increasing address
00275  *                 order, which results in significant savings.
00276  *
00277  *              b) It facilitates checking for adjacent dirty entries when
00278  *                 attempting to evict entries from the cache.  While we
00279  *                 don't use this at present, I hope that this will allow
00280  *                 some optimizations when I get to it.
00281  *
00282  * With the addition of the fractal heap, the cache must now deal with
00283  * the case in which entries may be dirtied, renamed, or have their sizes
00284  * changed during a flush.  To allow sanity checks in this situation, the
00285  * following two fields have been added.  They are only compiled in when
00286  * H5C_DO_SANITY_CHECKS is TRUE.
00287  *
00288  * slist_len_increase: Number of entries that have been added to the
00289  *              slist since the last time this field was set to zero.
00290  *
00291  * slist_size_increase: Total size of all entries that have been added
00292  *              to the slist since the last time this field was set to
00293  *              zero.
00294  *
00295  *
00296  * When a cache entry is protected, it must be removed from the LRU
00297  * list(s) as it cannot be either flushed or evicted until it is unprotected.
00298  * The following fields are used to implement the protected list (pl).
00299  *
00300  * pl_len:      Number of entries currently residing on the protected list.
00301  *
00302  * pl_size:     Number of bytes of cache entries currently residing on the
00303  *              protected list.
00304  *
00305  * pl_head_ptr: Pointer to the head of the doubly linked list of protected
00306  *              entries.  Note that cache entries on this list are linked
00307  *              by their next and prev fields.
00308  *
00309  *              This field is NULL if the list is empty.
00310  *
00311  * pl_tail_ptr: Pointer to the tail of the doubly linked list of protected
00312  *              entries.  Note that cache entries on this list are linked
00313  *              by their next and prev fields.
00314  *
00315  *              This field is NULL if the list is empty.
00316  *
00317  *
00318  * For very frequently used entries, the protect/unprotect overhead can
00319  * become burdensome.  To avoid this overhead, I have modified the cache
00320  * to allow entries to be "pinned".  A pinned entry is similar to a
00321  * protected entry, in the sense that it cannot be evicted, and that
00322  * the entry can be modified at any time.
00323  *
00324  * Pinning an entry has the following implications:
00325  *
00326  *      1) A pinned entry cannot be evicted.  Thus unprotected
00327  *         pinned entries reside in the pinned entry list, instead
00328  *         of the LRU list(s) (or other lists maintained by the current
00329  *         replacement policy code).
00330  *
00331  *      2) A pinned entry can be accessed or modified at any time.
00332  *         Therefore, the cache must check with the entry owner
00333  *         before flushing it.  If permission is denied, the
00334  *         cache just skips the entry in the flush.
00335  *
00336  *      3) A pinned entry can be marked as dirty (and possibly
00337  *         change size) while it is unprotected.
00338  *
00339  *      4) The flush-destroy code must allow pinned entries to
00340  *         be unpinned (and possibly unprotected) during the
00341  *         flush.
00342  *
00343  * Since pinned entries cannot be evicted, they must be kept on a pinned
00344  * entry list, instead of being entrusted to the replacement policy code.
00345  *
00346  * Maintaining the pinned entry list requires the following fields:
00347  *
00348  * pel_len:     Number of entries currently residing on the pinned
00349  *              entry list.
00350  *
00351  * pel_size:    Number of bytes of cache entries currently residing on
00352  *              the pinned entry list.
00353  *
00354  * pel_head_ptr: Pointer to the head of the doubly linked list of pinned
00355  *              but not protected entries.  Note that cache entries on
00356  *              this list are linked by their next and prev fields.
00357  *
00358  *              This field is NULL if the list is empty.
00359  *
00360  * pel_tail_ptr: Pointer to the tail of the doubly linked list of pinned
00361  *              but not protected entries.  Note that cache entries on
00362  *              this list are linked by their next and prev fields.
00363  *
00364  *              This field is NULL if the list is empty.
00365  *
00366  *
00367  * The cache must have a replacement policy, and the fields supporting this
00368  * policy must be accessible from this structure.
00369  *
00370  * While there has been interest in several replacement policies for
00371  * this cache, the initial development schedule is tight.  Thus I have
00372  * elected to support only a modified LRU policy for the first cut.
00373  *
00374  * To further simplify matters, I have simply included the fields needed
00375  * by the modified LRU in this structure.  When and if we add support for
00376  * other policies, it will probably be easiest to just add the necessary
00377  * fields to this structure as well -- we only create one instance of this
00378  * structure per file, so the overhead is not excessive.
00379  *
00380  *
00381  * Fields supporting the modified LRU policy:
00382  *
00383  * See most any OS text for a discussion of the LRU replacement policy.
00384  *
00385  * When operating in parallel mode, we must ensure that a read does not
00386  * cause a write.  If it does, the process will hang, as the write will
00387  * be collective and the other processes will not know to participate.
00388  *
00389  * To deal with this issue, I have modified the usual LRU policy by adding
00390  * clean and dirty LRU lists to the usual LRU list.
00391  *
00392  * The clean LRU list is simply the regular LRU list with all dirty cache
00393  * entries removed.
00394  *
00395  * Similarly, the dirty LRU list is the regular LRU list with all the clean
00396  * cache entries removed.
00397  *
00398  * When reading in parallel mode, we evict from the clean LRU list only.
00399  * This implies that we must try to ensure that the clean LRU list is
00400  * reasonably well stocked at all times.
00401  *
00402  * We attempt to do this by trying to flush enough entries on each write
00403  * to keep the cLRU_list_size >= min_clean_size.
00404  *
00405  * Even if we start with a completely clean cache, a sequence of protects
00406  * without unprotects can empty the clean LRU list.  In this case, the
00407  * cache must grow temporarily.  At the next write, we will attempt to
00408  * evict enough entries to reduce index_size to less than max_cache_size.
00409  * While this will usually be possible, all bets are off if enough entries
00410  * are protected.
00411  *
00412  * Discussions of the individual fields used by the modified LRU replacement
00413  * policy follow:
00414  *
00415  * LRU_list_len:  Number of cache entries currently on the LRU list.
00416  *
00417  *              Observe that LRU_list_len + pl_len must always equal
00418  *              index_len.
00419  *
00420  * LRU_list_size:  Number of bytes of cache entries currently residing on the
00421  *              LRU list.
00422  *
00423  *              Observe that LRU_list_size + pl_size must always equal
00424  *              index_size.
00425  *
00426  * LRU_head_ptr:  Pointer to the head of the doubly linked LRU list.  Cache
00427  *              entries on this list are linked by their next and prev fields.
00428  *
00429  *              This field is NULL if the list is empty.
00430  *
00431  * LRU_tail_ptr:  Pointer to the tail of the doubly linked LRU list.  Cache
00432  *              entries on this list are linked by their next and prev fields.
00433  *
00434  *              This field is NULL if the list is empty.
00435  *
00436  * cLRU_list_len: Number of cache entries currently on the clean LRU list.
00437  *
00438  *              Observe that cLRU_list_len + dLRU_list_len must always
00439  *              equal LRU_list_len.
00440  *
00441  * cLRU_list_size:  Number of bytes of cache entries currently residing on
00442  *              the clean LRU list.
00443  *
00444  *              Observe that cLRU_list_size + dLRU_list_size must always
00445  *              equal LRU_list_size.
00446  *
00447  * cLRU_head_ptr:  Pointer to the head of the doubly linked clean LRU list.
00448  *              Cache entries on this list are linked by their aux_next and
00449  *              aux_prev fields.
00450  *
00451  *              This field is NULL if the list is empty.
00452  *
00453  * cLRU_tail_ptr:  Pointer to the tail of the doubly linked clean LRU list.
00454  *              Cache entries on this list are linked by their aux_next and
00455  *              aux_prev fields.
00456  *
00457  *              This field is NULL if the list is empty.
00458  *
00459  * dLRU_list_len: Number of cache entries currently on the dirty LRU list.
00460  *
00461  *              Observe that cLRU_list_len + dLRU_list_len must always
00462  *              equal LRU_list_len.
00463  *
00464  * dLRU_list_size:  Number of cache entries currently on the dirty LRU list.
00465  *
00466  *              Observe that cLRU_list_len + dLRU_list_len must always
00467  *              equal LRU_list_len.
00468  *
00469  * dLRU_head_ptr:  Pointer to the head of the doubly linked dirty LRU list.
00470  *              Cache entries on this list are linked by their aux_next and
00471  *              aux_prev fields.
00472  *
00473  *              This field is NULL if the list is empty.
00474  *
00475  * dLRU_tail_ptr:  Pointer to the tail of the doubly linked dirty LRU list.
00476  *              Cache entries on this list are linked by their aux_next and
00477  *              aux_prev fields.
00478  *
00479  *              This field is NULL if the list is empty.
00480  *
00481  *
00482  * Automatic cache size adjustment:
00483  *
00484  * While the default cache size is adequate for most cases, we can run into
00485  * cases where the default is too small.  Ideally, we will let the user
00486  * adjust the cache size as required.  However, this is not possible in all
00487  * cases.  Thus I have added automatic cache size adjustment code.
00488  *
00489  * The configuration for the automatic cache size adjustment is stored in
00490  * the structure described below:
00491  *
00492  * size_increase_possible:  Depending on the configuration data given
00493  *              in the resize_ctl field, it may or may not be possible
00494  *              to increase the size of the cache.  Rather than test for
00495  *              all the ways this can happen, we simply set this flag when
00496  *              we receive a new configuration.
00497  *
00498  * flash_size_increase_possible: Depending on the configuration data given
00499  *              in the resize_ctl field, it may or may not be possible
00500  *              for a flash size increase to occur.  We set this flag
00501  *              whenever we receive a new configuration so as to avoid
00502  *              repeated calculations.
00503  *
00504  * flash_size_increase_threshold: If a flash cache size increase is possible,
00505  *              this field is used to store the minimum size of a new entry
00506  *              or size increase needed to trigger a flash cache size
00507  *              increase.  Note that this field must be updated whenever
00508  *              the size of the cache is changed.
00509  *
00510  * size_decrease_possible:  Depending on the configuration data given
00511  *              in the resize_ctl field, it may or may not be possible
00512  *              to decrease the size of the cache.  Rather than test for
00513  *              all the ways this can happen, we simply set this flag when
00514  *              we receive a new configuration.
00515  *
00516  * cache_full:  Boolean flag used to keep track of whether the cache is
00517  *              full, so we can refrain from increasing the size of a
00518  *              cache which hasn't used up the space alotted to it.
00519  *
00520  *              The field is initialized to FALSE, and then set to TRUE
00521  *              whenever we attempt to make space in the cache.
00522  *
00523  * resize_enabled:  This is another convenience flag which is set whenever
00524  *              a new set of values for resize_ctl are provided.  Very
00525  *              simply,
00526  *
00527  *                  resize_enabled = size_increase_possible ||
00528  *                                   size_decrease_possible;
00529  *
00530  * size_decreased:  Boolean flag set to TRUE whenever the maximun cache
00531  *              size is decreased.  The flag triggers a call to
00532  *              H5C_make_space_in_cache() on the next call to H5C_protect().
00533  *
00534  * resize_ctl:  Instance of H5C_auto_size_ctl_t containing configuration
00535  *              data for automatic cache resizing.
00536  *
00537  * epoch_markers_active:  Integer field containing the number of epoch
00538  *              markers currently in use in the LRU list.  This value
00539  *              must be in the range [0, H5C__MAX_EPOCH_MARKERS - 1].
00540  *
00541  * epoch_marker_active:  Array of boolean of length H5C__MAX_EPOCH_MARKERS.
00542  *              This array is used to track which epoch markers are currently
00543  *              in use.
00544  *
00545  * epoch_marker_ringbuf:  Array of int of length H5C__MAX_EPOCH_MARKERS + 1.
00546  *
00547  *              To manage the epoch marker cache entries, it is necessary
00548  *              to track their order in the LRU list.  This is done with
00549  *              epoch_marker_ringbuf.  When markers are inserted at the
00550  *              head of the LRU list, the index of the marker in the
00551  *              epoch_markers array is inserted at the tail of the ring
00552  *              buffer.  When it becomes the epoch_marker_active'th marker
00553  *              in the LRU list, it will have worked its way to the head
00554  *              of the ring buffer as well.  This allows us to remove it
00555  *              without scanning the LRU list if such is required.
00556  *
00557  * epoch_marker_ringbuf_first: Integer field containing the index of the
00558  *              first entry in the ring buffer.
00559  *
00560  * epoch_marker_ringbuf_last: Integer field containing the index of the
00561  *              last entry in the ring buffer.
00562  *
00563  * epoch_marker_ringbuf_size: Integer field containing the number of entries
00564  *              in the ring buffer.
00565  *
00566  * epoch_markers:  Array of instances of H5C_cache_entry_t of length
00567  *              H5C__MAX_EPOCH_MARKERS.  The entries are used as markers
00568  *              in the LRU list to identify cache entries that haven't
00569  *              been accessed for some (small) specified number of
00570  *              epochs.  These entries (if any) can then be evicted and
00571  *              the cache size reduced -- ideally without evicting any
00572  *              of the current working set.  Needless to say, the epoch
00573  *              length and the number of epochs before an unused entry
00574  *              must be chosen so that all, or almost all, the working
00575  *              set will be accessed before the limit.
00576  *
00577  *              Epoch markers only appear in the LRU list, never in
00578  *              the index or slist.  While they are of type
00579  *              H5C__EPOCH_MARKER_TYPE, and have associated class
00580  *              functions, these functions should never be called.
00581  *
00582  *              The addr fields of these instances of H5C_cache_entry_t
00583  *              are set to the index of the instance in the epoch_markers
00584  *              array, the size is set to 0, and the type field points
00585  *              to the constant structure epoch_marker_class defined
00586  *              in H5C.c.  The next and prev fields are used as usual
00587  *              to link the entry into the LRU list.
00588  *
00589  *              All other fields are unused.
00590  *
00591  *
00592  * Cache hit rate collection fields:
00593  *
00594  * We supply the current cache hit rate on request, so we must keep a
00595  * simple cache hit rate computation regardless of whether statistics
00596  * collection is enabled.  The following fields support this capability.
00597  *
00598  * cache_hits: Number of cache hits since the last time the cache hit
00599  *      rate statistics were reset.  Note that when automatic cache
00600  *      re-sizing is enabled, this field will be reset every automatic
00601  *      resize epoch.
00602  *
00603  * cache_accesses: Number of times the cache has been accessed while
00604  *      since the last since the last time the cache hit rate statistics
00605  *      were reset.  Note that when automatic cache re-sizing is enabled,
00606  *      this field will be reset every automatic resize epoch.
00607  *
00608  *
00609  * Statistics collection fields:
00610  *
00611  * When enabled, these fields are used to collect statistics as described
00612  * below.  The first set are collected only when H5C_COLLECT_CACHE_STATS
00613  * is true.
00614  *
00615  * hits:        Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00616  *              are used to record the number of times an entry with type id
00617  *              equal to the array index has been in cache when requested in
00618  *              the current epoch.
00619  *
00620  * misses:      Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00621  *              are used to record the number of times an entry with type id
00622  *              equal to the array index has not been in cache when
00623  *              requested in the current epoch.
00624  *
00625  * write_protects:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The
00626  *              cells are used to record the number of times an entry with
00627  *              type id equal to the array index has been write protected
00628  *              in the current epoch.
00629  *
00630  *              Observe that (hits + misses) = (write_protects + read_protects).
00631  *
00632  * read_protects: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00633  *              are used to record the number of times an entry with type id
00634  *              equal to the array index has been read protected in the
00635  *              current epoch.
00636  *
00637  *              Observe that (hits + misses) = (write_protects + read_protects).
00638  *
00639  * max_read_protects:  Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.
00640  *              The cells are used to maximum number of simultaneous read
00641  *              protects on any entry with type id equal to the array index
00642  *              in the current epoch.
00643  *
00644  * insertions:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00645  *              are used to record the number of times an entry with type
00646  *              id equal to the array index has been inserted into the
00647  *              cache in the current epoch.
00648  *
00649  * pinned_insertions:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
00650  *              The cells are used to record the number of times an entry
00651  *              with type id equal to the array index has been inserted
00652  *              pinned into the cache in the current epoch.
00653  *
00654  * clears:      Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00655  *              are used to record the number of times an entry with type
00656  *              id equal to the array index has been cleared in the current
00657  *              epoch.
00658  *
00659  * flushes:     Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00660  *              are used to record the number of times an entry with type id
00661  *              equal to the array index has been written to disk in the
00662  *              current epoch.
00663  *
00664  * evictions:   Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00665  *              are used to record the number of times an entry with type id
00666  *              equal to the array index has been evicted from the cache in
00667  *              the current epoch.
00668  *
00669  * renames:     Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00670  *              are used to record the number of times an entry with type
00671  *              id equal to the array index has been renamed in the current
00672  *              epoch.
00673  *
00674  * entry_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
00675  *              The cells are used to record the number of times an entry
00676  *              with type id equal to the array index has been renamed
00677  *              during its flush callback in the current epoch.
00678  *
00679  * cache_flush_renames: Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
00680  *              The cells are used to record the number of times an entry
00681  *              with type id equal to the array index has been renamed
00682  *              during a cache flush in the current epoch.
00683  *
00684  * pins:        Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00685  *              are used to record the number of times an entry with type
00686  *              id equal to the array index has been pinned in the current
00687  *              epoch.
00688  *
00689  * unpins:      Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00690  *              are used to record the number of times an entry with type
00691  *              id equal to the array index has been unpinned in the current
00692  *              epoch.
00693  *
00694  * dirty_pins:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00695  *              are used to record the number of times an entry with type
00696  *              id equal to the array index has been marked dirty while pinned
00697  *              in the current epoch.
00698  *
00699  * pinned_flushes:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The
00700  *              cells are used to record the number of times an  entry
00701  *              with type id equal to the array index has been flushed while
00702  *              pinned in the current epoch.
00703  *
00704  * pinned_cleared:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.  The
00705  *              cells are used to record the number of times an  entry
00706  *              with type id equal to the array index has been cleared while
00707  *              pinned in the current epoch.
00708  *
00709  * size_increases:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
00710  *              The cells are used to record the number of times an entry
00711  *              with type id equal to the array index has increased in
00712  *              size in the current epoch.
00713  *
00714  * size_decreases:  Array of int64 of length H5C__MAX_NUM_TYPE_IDS + 1.
00715  *              The cells are used to record the number of times an entry
00716  *              with type id equal to the array index has decreased in
00717  *              size in the current epoch.
00718  *
00719  * entry_flush_size_changes:  Array of int64 of length
00720  *              H5C__MAX_NUM_TYPE_IDS + 1.  The cells are used to record
00721  *              the number of times an entry with type id equal to the
00722  *              array index has changed size while in its flush callback.
00723  *
00724  * cache_flush_size_changes:  Array of int64 of length
00725  *              H5C__MAX_NUM_TYPE_IDS + 1.  The cells are used to record
00726  *              the number of times an entry with type id equal to the
00727  *              array index has changed size during a cache flush
00728  *
00729  * total_ht_insertions: Number of times entries have been inserted into the
00730  *              hash table in the current epoch.
00731  *
00732  * total_ht_deletions: Number of times entries have been deleted from the
00733  *              hash table in the current epoch.
00734  *
00735  * successful_ht_searches: int64 containing the total number of successful
00736  *              searches of the hash table in the current epoch.
00737  *
00738  * total_successful_ht_search_depth: int64 containing the total number of
00739  *              entries other than the targets examined in successful
00740  *              searches of the hash table in the current epoch.
00741  *
00742  * failed_ht_searches: int64 containing the total number of unsuccessful
00743  *              searches of the hash table in the current epoch.
00744  *
00745  * total_failed_ht_search_depth: int64 containing the total number of
00746  *              entries examined in unsuccessful searches of the hash
00747  *              table in the current epoch.
00748  *
00749  * max_index_len:  Largest value attained by the index_len field in the
00750  *              current epoch.
00751  *
00752  * max_index_size:  Largest value attained by the index_size field in the
00753  *              current epoch.
00754  *
00755  * max_clean_index_size: Largest value attained by the clean_index_size field
00756  *              in the current epoch.
00757  *
00758  * max_dirty_index_size: Largest value attained by the dirty_index_size field
00759  *              in the current epoch.
00760  *
00761  * max_slist_len:  Largest value attained by the slist_len field in the
00762  *              current epoch.
00763  *
00764  * max_slist_size:  Largest value attained by the slist_size field in the
00765  *              current epoch.
00766  *
00767  * max_pl_len:  Largest value attained by the pl_len field in the
00768  *              current epoch.
00769  *
00770  * max_pl_size: Largest value attained by the pl_size field in the
00771  *              current epoch.
00772  *
00773  * max_pel_len: Largest value attained by the pel_len field in the
00774  *              current epoch.
00775  *
00776  * max_pel_size: Largest value attained by the pel_size field in the
00777  *              current epoch.
00778  *
00779  * calls_to_msic: Total number of calls to H5C_make_space_in_cache
00780  *
00781  * total_entries_skipped_in_msic: Number of clean entries skipped while
00782  *              enforcing the min_clean_fraction in H5C_make_space_in_cache().
00783  *
00784  * total_entries_scanned_in_msic: Number of clean entries skipped while
00785  *              enforcing the min_clean_fraction in H5C_make_space_in_cache().
00786  *
00787  * max_entries_skipped_in_msic: Maximum number of clean entries skipped
00788  *              in any one call to H5C_make_space_in_cache().
00789  *
00790  * max_entries_scanned_in_msic: Maximum number of entries scanned over
00791  *              in any one call to H5C_make_space_in_cache().
00792  *
00793  * entries_scanned_to_make_space: Number of entries scanned only when looking
00794  *              for entries to evict in order to make space in cache.
00795 
00796  * The remaining stats are collected only when both H5C_COLLECT_CACHE_STATS
00797  * and H5C_COLLECT_CACHE_ENTRY_STATS are true.
00798  *
00799  * max_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00800  *              are used to record the maximum number of times any single
00801  *              entry with type id equal to the array index has been
00802  *              accessed in the current epoch.
00803  *
00804  * min_accesses: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00805  *              are used to record the minimum number of times any single
00806  *              entry with type id equal to the array index has been
00807  *              accessed in the current epoch.
00808  *
00809  * max_clears:  Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00810  *              are used to record the maximum number of times any single
00811  *              entry with type id equal to the array index has been cleared
00812  *              in the current epoch.
00813  *
00814  * max_flushes: Array of int32 of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00815  *              are used to record the maximum number of times any single
00816  *              entry with type id equal to the array index has been
00817  *              flushed in the current epoch.
00818  *
00819  * max_size:    Array of size_t of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00820  *              are used to record the maximum size of any single entry
00821  *              with type id equal to the array index that has resided in
00822  *              the cache in the current epoch.
00823  *
00824  * max_pins:    Array of size_t of length H5C__MAX_NUM_TYPE_IDS + 1.  The cells
00825  *              are used to record the maximum number of times that any single
00826  *              entry with type id equal to the array index that has been
00827  *              marked as pinned in the cache in the current epoch.
00828  *
00829  *
00830  * Fields supporting testing:
00831  *
00832  * For test purposes, it is useful to turn off some asserts and sanity
00833  * checks.  The following flags support this.
00834  *
00835  * skip_file_checks:  Boolean flag used to skip sanity checks on file
00836  *              parameters passed to the cache.  In the test bed, there
00837  *              is no reason to have a file open, as the cache proper
00838  *              just passes these parameters through without using them.
00839  *
00840  *              When this flag is set, all sanity checks on the file
00841  *              parameters are skipped.  The field defaults to FALSE.
00842  *
00843  * skip_dxpl_id_checks:  Boolean flag used to skip sanity checks on the
00844  *              dxpl_id parameters passed to the cache.  These are not
00845  *              used directly by the cache, so skipping the checks
00846  *              simplifies the test bed.
00847  *
00848  *              When this flag is set, all sanity checks on the dxpl_id
00849  *              parameters are skipped.  The field defaults to FALSE.
00850  *
00851  * prefix       Array of char used to prefix debugging output.  The
00852  *              field is intended to allow marking of output of with
00853  *              the processes mpi rank.
00854  *
00855  ****************************************************************************/
00856 
00857 #define H5C__HASH_TABLE_LEN     (64 * 1024) /* must be a power of 2 */
00858 
00859 #define H5C__H5C_T_MAGIC        0x005CAC0E
00860 #define H5C__MAX_NUM_TYPE_IDS   18
00861 #define H5C__PREFIX_LEN         32
00862 
00863 struct H5C_t
00864 {
00865     uint32_t                    magic;
00866 
00867     hbool_t                     flush_in_progress;
00868 
00869     FILE *                      trace_file_ptr;
00870 
00871     void *                      aux_ptr;
00872 
00873     int32_t                     max_type_id;
00874     const char *                (* type_name_table_ptr);
00875 
00876     size_t                      max_cache_size;
00877     size_t                      min_clean_size;
00878 
00879     H5C_write_permitted_func_t  check_write_permitted;
00880     hbool_t                     write_permitted;
00881 
00882     H5C_log_flush_func_t        log_flush;
00883 
00884     hbool_t                     evictions_enabled;
00885 
00886     int32_t                     index_len;
00887     size_t                      index_size;
00888     size_t                      clean_index_size;
00889     size_t                      dirty_index_size;
00890     H5C_cache_entry_t *         (index[H5C__HASH_TABLE_LEN]);
00891 
00892 
00893     int32_t                     slist_len;
00894     size_t                      slist_size;
00895     H5SL_t *                    slist_ptr;
00896 #if H5C_DO_SANITY_CHECKS
00897     int64_t                     slist_len_increase;
00898     int64_t                     slist_size_increase;
00899 #endif /* H5C_DO_SANITY_CHECKS */
00900 
00901     int32_t                     pl_len;
00902     size_t                      pl_size;
00903     H5C_cache_entry_t *         pl_head_ptr;
00904     H5C_cache_entry_t *         pl_tail_ptr;
00905 
00906     int32_t                     pel_len;
00907     size_t                      pel_size;
00908     H5C_cache_entry_t *         pel_head_ptr;
00909     H5C_cache_entry_t *         pel_tail_ptr;
00910 
00911     int32_t                     LRU_list_len;
00912     size_t                      LRU_list_size;
00913     H5C_cache_entry_t *         LRU_head_ptr;
00914     H5C_cache_entry_t *         LRU_tail_ptr;
00915 
00916     int32_t                     cLRU_list_len;
00917     size_t                      cLRU_list_size;
00918     H5C_cache_entry_t *         cLRU_head_ptr;
00919     H5C_cache_entry_t *         cLRU_tail_ptr;
00920 
00921     int32_t                     dLRU_list_len;
00922     size_t                      dLRU_list_size;
00923     H5C_cache_entry_t *         dLRU_head_ptr;
00924     H5C_cache_entry_t *         dLRU_tail_ptr;
00925 
00926     hbool_t                     size_increase_possible;
00927     hbool_t                     flash_size_increase_possible;
00928     size_t                      flash_size_increase_threshold;
00929     hbool_t                     size_decrease_possible;
00930     hbool_t                     resize_enabled;
00931     hbool_t                     cache_full;
00932     hbool_t                     size_decreased;
00933     H5C_auto_size_ctl_t         resize_ctl;
00934 
00935     int32_t                     epoch_markers_active;
00936     hbool_t                     epoch_marker_active[H5C__MAX_EPOCH_MARKERS];
00937     int32_t                     epoch_marker_ringbuf[H5C__MAX_EPOCH_MARKERS+1];
00938     int32_t                     epoch_marker_ringbuf_first;
00939     int32_t                     epoch_marker_ringbuf_last;
00940     int32_t                     epoch_marker_ringbuf_size;
00941     H5C_cache_entry_t           epoch_markers[H5C__MAX_EPOCH_MARKERS];
00942 
00943     int64_t                     cache_hits;
00944     int64_t                     cache_accesses;
00945 
00946 #if H5C_COLLECT_CACHE_STATS
00947 
00948     /* stats fields */
00949     int64_t                     hits[H5C__MAX_NUM_TYPE_IDS + 1];
00950     int64_t                     misses[H5C__MAX_NUM_TYPE_IDS + 1];
00951     int64_t                     write_protects[H5C__MAX_NUM_TYPE_IDS + 1];
00952     int64_t                     read_protects[H5C__MAX_NUM_TYPE_IDS + 1];
00953     int32_t                     max_read_protects[H5C__MAX_NUM_TYPE_IDS + 1];
00954     int64_t                     insertions[H5C__MAX_NUM_TYPE_IDS + 1];
00955     int64_t                     pinned_insertions[H5C__MAX_NUM_TYPE_IDS + 1];
00956     int64_t                     clears[H5C__MAX_NUM_TYPE_IDS + 1];
00957     int64_t                     flushes[H5C__MAX_NUM_TYPE_IDS + 1];
00958     int64_t                     evictions[H5C__MAX_NUM_TYPE_IDS + 1];
00959     int64_t                     renames[H5C__MAX_NUM_TYPE_IDS + 1];
00960     int64_t                     entry_flush_renames[H5C__MAX_NUM_TYPE_IDS + 1];
00961     int64_t                     cache_flush_renames[H5C__MAX_NUM_TYPE_IDS + 1];
00962     int64_t                     pins[H5C__MAX_NUM_TYPE_IDS + 1];
00963     int64_t                     unpins[H5C__MAX_NUM_TYPE_IDS + 1];
00964     int64_t                     dirty_pins[H5C__MAX_NUM_TYPE_IDS + 1];
00965     int64_t                     pinned_flushes[H5C__MAX_NUM_TYPE_IDS + 1];
00966     int64_t                     pinned_clears[H5C__MAX_NUM_TYPE_IDS + 1];
00967     int64_t                     size_increases[H5C__MAX_NUM_TYPE_IDS + 1];
00968     int64_t                     size_decreases[H5C__MAX_NUM_TYPE_IDS + 1];
00969     int64_t                     entry_flush_size_changes
00970                                         [H5C__MAX_NUM_TYPE_IDS + 1];
00971     int64_t                     cache_flush_size_changes
00972                                         [H5C__MAX_NUM_TYPE_IDS + 1];
00973 
00974     int64_t                     total_ht_insertions;
00975     int64_t                     total_ht_deletions;
00976     int64_t                     successful_ht_searches;
00977     int64_t                     total_successful_ht_search_depth;
00978     int64_t                     failed_ht_searches;
00979     int64_t                     total_failed_ht_search_depth;
00980 
00981     int32_t                     max_index_len;
00982     size_t                      max_index_size;
00983     size_t                      max_clean_index_size;
00984     size_t                      max_dirty_index_size;
00985 
00986     int32_t                     max_slist_len;
00987     size_t                      max_slist_size;
00988 
00989     int32_t                     max_pl_len;
00990     size_t                      max_pl_size;
00991 
00992     int32_t                     max_pel_len;
00993     size_t                      max_pel_size;
00994 
00995     int64_t                     calls_to_msic;
00996     int64_t                     total_entries_skipped_in_msic;
00997     int64_t                     total_entries_scanned_in_msic;
00998     int32_t                     max_entries_skipped_in_msic;
00999     int32_t                     max_entries_scanned_in_msic;
01000     int64_t                     entries_scanned_to_make_space;
01001 
01002 #if H5C_COLLECT_CACHE_ENTRY_STATS
01003 
01004     int32_t                     max_accesses[H5C__MAX_NUM_TYPE_IDS + 1];
01005     int32_t                     min_accesses[H5C__MAX_NUM_TYPE_IDS + 1];
01006     int32_t                     max_clears[H5C__MAX_NUM_TYPE_IDS + 1];
01007     int32_t                     max_flushes[H5C__MAX_NUM_TYPE_IDS + 1];
01008     size_t                      max_size[H5C__MAX_NUM_TYPE_IDS + 1];
01009     int32_t                     max_pins[H5C__MAX_NUM_TYPE_IDS + 1];
01010 
01011 #endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
01012 
01013 #endif /* H5C_COLLECT_CACHE_STATS */
01014 
01015     hbool_t                     skip_file_checks;
01016     hbool_t                     skip_dxpl_id_checks;
01017     char                        prefix[H5C__PREFIX_LEN];
01018 };
01019 
01020 
01021 /****************************************************************************/
01022 /***************************** Macro Definitions ****************************/
01023 /****************************************************************************/
01024 
01025 
01026 /****************************************************************************
01027  *
01028  * We maintain doubly linked lists of instances of H5C_cache_entry_t for a
01029  * variety of reasons -- protected list, LRU list, and the clean and dirty
01030  * LRU lists at present.  The following macros support linking and unlinking
01031  * of instances of H5C_cache_entry_t by both their regular and auxilary next
01032  * and previous pointers.
01033  *
01034  * The size and length fields are also maintained.
01035  *
01036  * Note that the relevant pair of prev and next pointers are presumed to be
01037  * NULL on entry in the insertion macros.
01038  *
01039  * Finally, observe that the sanity checking macros evaluate to the empty
01040  * string when H5C_DO_SANITY_CHECKS is FALSE.  They also contain calls
01041  * to the HGOTO_ERROR macro, which may not be appropriate in all cases.
01042  * If so, we will need versions of the insertion and deletion macros which
01043  * do not reference the sanity checking macros.
01044  *                                                      JRM - 5/5/04
01045  *
01046  * Changes:
01047  *
01048  *  - Removed the line:
01049  *
01050  *        ( ( (Size) == (entry_ptr)->size ) && ( (len) != 1 ) ) ||
01051  *
01052  *    from the H5C__DLL_PRE_REMOVE_SC macro.  With the addition of the
01053  *    epoch markers used in the age out based cache size reduction algorithm,
01054  *    this invarient need not hold, as the epoch markers are of size 0.
01055  *
01056  *    One could argue that I should have given the epoch markers a positive
01057  *    size, but this would break the index_size = LRU_list_size + pl_size
01058  *    + pel_size invarient.
01059  *
01060  *    Alternatively, I could pass the current decr_mode in to the macro,
01061  *    and just skip the check whenever epoch markers may be in use.
01062  *
01063  *    However, any size errors should be caught when the cache is flushed
01064  *    and destroyed.  Until we are tracking such an error, this should be
01065  *    good enough.
01066  *                                                     JRM - 12/9/04
01067  *
01068  *
01069  *  - In the H5C__DLL_PRE_INSERT_SC macro, replaced the lines:
01070  *
01071  *    ( ( (len) == 1 ) &&
01072  *      ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) ||
01073  *        ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
01074  *      )
01075  *    ) ||
01076  *
01077  *    with:
01078  *
01079  *    ( ( (len) == 1 ) &&
01080  *      ( ( (head_ptr) != (tail_ptr) ) ||
01081  *        ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
01082  *      )
01083  *    ) ||
01084  *
01085  *    Epoch markers have size 0, so we can now have a non-empty list with
01086  *    zero size.  Hence the "( (Size) <= 0 )" clause cause false failures
01087  *    in the sanity check.  Since "Size" is typically a size_t, it can't
01088  *    take on negative values, and thus the revised clause "( (Size) < 0 )"
01089  *    caused compiler warnings.
01090  *                                                     JRM - 12/22/04
01091  *
01092  *  - In the H5C__DLL_SC macro, replaced the lines:
01093  *
01094  *    ( ( (len) == 1 ) &&
01095  *      ( ( (head_ptr) != (tail_ptr) ) || ( (cache_ptr)->size <= 0 ) ||
01096  *        ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
01097  *      )
01098  *    ) ||
01099  *
01100  *    with
01101  *
01102  *    ( ( (len) == 1 ) &&
01103  *      ( ( (head_ptr) != (tail_ptr) ) ||
01104  *        ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )
01105  *      )
01106  *    ) ||
01107  *
01108  *    Epoch markers have size 0, so we can now have a non-empty list with
01109  *    zero size.  Hence the "( (Size) <= 0 )" clause cause false failures
01110  *    in the sanity check.  Since "Size" is typically a size_t, it can't
01111  *    take on negative values, and thus the revised clause "( (Size) < 0 )"
01112  *    caused compiler warnings.
01113  *                                                     JRM - 1/10/05
01114  *
01115  *  - Added the H5C__DLL_UPDATE_FOR_SIZE_CHANGE macro and the associated
01116  *    sanity checking macros.  These macro are used to update the size of
01117  *    a DLL when one of its entries changes size.
01118  *
01119  *                                                      JRM - 9/8/05
01120  *
01121  ****************************************************************************/
01122 
01123 #if H5C_DO_SANITY_CHECKS
01124 
01125 #define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
01126 if ( ( (head_ptr) == NULL ) ||                                               \
01127      ( (tail_ptr) == NULL ) ||                                               \
01128      ( (entry_ptr) == NULL ) ||                                              \
01129      ( (len) <= 0 ) ||                                                       \
01130      ( (Size) < (entry_ptr)->size ) ||                                       \
01131      ( ( (entry_ptr)->prev == NULL ) && ( (head_ptr) != (entry_ptr) ) ) ||   \
01132      ( ( (entry_ptr)->next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) ||   \
01133      ( ( (len) == 1 ) &&                                                     \
01134        ( ! ( ( (head_ptr) == (entry_ptr) ) &&                                \
01135              ( (tail_ptr) == (entry_ptr) ) &&                                \
01136              ( (entry_ptr)->next == NULL ) &&                                \
01137              ( (entry_ptr)->prev == NULL ) &&                                \
01138              ( (Size) == (entry_ptr)->size )                                 \
01139            )                                                                 \
01140        )                                                                     \
01141      )                                                                       \
01142    ) {                                                                       \
01143     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre remove SC failed")     \
01144 }
01145 
01146 #define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv)                   \
01147 if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) &&           \
01148        ( (head_ptr) != (tail_ptr) )                                      \
01149      ) ||                                                                \
01150      ( (len) < 0 ) ||                                                    \
01151      ( (Size) < 0 ) ||                                                   \
01152      ( ( (len) == 1 ) &&                                                 \
01153        ( ( (head_ptr) != (tail_ptr) ) ||                                 \
01154          ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )        \
01155        )                                                                 \
01156      ) ||                                                                \
01157      ( ( (len) >= 1 ) &&                                                 \
01158        ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) ||       \
01159          ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL )          \
01160        )                                                                 \
01161      )                                                                   \
01162    ) {                                                                   \
01163     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL sanity check failed")  \
01164 }
01165 
01166 #define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv) \
01167 if ( ( (entry_ptr) == NULL ) ||                                              \
01168      ( (entry_ptr)->next != NULL ) ||                                        \
01169      ( (entry_ptr)->prev != NULL ) ||                                        \
01170      ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) &&               \
01171        ( (head_ptr) != (tail_ptr) )                                          \
01172      ) ||                                                                    \
01173      ( (len) < 0 ) ||                                                        \
01174      ( ( (len) == 1 ) &&                                                     \
01175        ( ( (head_ptr) != (tail_ptr) ) ||                                     \
01176          ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )            \
01177        )                                                                     \
01178      ) ||                                                                    \
01179      ( ( (len) >= 1 ) &&                                                     \
01180        ( ( (head_ptr) == NULL ) || ( (head_ptr)->prev != NULL ) ||           \
01181          ( (tail_ptr) == NULL ) || ( (tail_ptr)->next != NULL )              \
01182        )                                                                     \
01183      )                                                                       \
01184    ) {                                                                       \
01185     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "DLL pre insert SC failed")     \
01186 }
01187 
01188 #define H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)    \
01189 if ( ( (dll_len) <= 0 ) ||                                                    \
01190      ( (dll_size) <= 0 ) ||                                                   \
01191      ( (old_size) <= 0 ) ||                                                   \
01192      ( (old_size) > (dll_size) ) ||                                           \
01193      ( (new_size) <= 0 ) ||                                                   \
01194      ( ( (dll_len) == 1 ) && ( (old_size) != (dll_size) ) ) ) {               \
01195     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL pre size update SC failed") \
01196 }
01197 
01198 #define H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)    \
01199 if ( ( (new_size) > (dll_size) ) ||                                            \
01200      ( ( (dll_len) == 1 ) && ( (new_size) != (dll_size) ) ) ) {                \
01201     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "DLL post size update SC failed") \
01202 }
01203 
01204 #else /* H5C_DO_SANITY_CHECKS */
01205 
01206 #define H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
01207 #define H5C__DLL_SC(head_ptr, tail_ptr, len, Size, fv)
01208 #define H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, fv)
01209 #define H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)
01210 #define H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)
01211 
01212 #endif /* H5C_DO_SANITY_CHECKS */
01213 
01214 
01215 #define H5C__DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
01216         H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size,    \
01217                                fail_val)                                    \
01218         if ( (head_ptr) == NULL )                                           \
01219         {                                                                   \
01220            (head_ptr) = (entry_ptr);                                        \
01221            (tail_ptr) = (entry_ptr);                                        \
01222         }                                                                   \
01223         else                                                                \
01224         {                                                                   \
01225            (tail_ptr)->next = (entry_ptr);                                  \
01226            (entry_ptr)->prev = (tail_ptr);                                  \
01227            (tail_ptr) = (entry_ptr);                                        \
01228         }                                                                   \
01229         (len)++;                                                            \
01230         (Size) += (entry_ptr)->size;
01231 
01232 #define H5C__DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
01233         H5C__DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size,     \
01234                                fail_val)                                     \
01235         if ( (head_ptr) == NULL )                                            \
01236         {                                                                    \
01237            (head_ptr) = (entry_ptr);                                         \
01238            (tail_ptr) = (entry_ptr);                                         \
01239         }                                                                    \
01240         else                                                                 \
01241         {                                                                    \
01242            (head_ptr)->prev = (entry_ptr);                                   \
01243            (entry_ptr)->next = (head_ptr);                                   \
01244            (head_ptr) = (entry_ptr);                                         \
01245         }                                                                    \
01246         (len)++;                                                             \
01247         (Size) += entry_ptr->size;
01248 
01249 #define H5C__DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val) \
01250         H5C__DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size,    \
01251                                fail_val)                                    \
01252         {                                                                   \
01253            if ( (head_ptr) == (entry_ptr) )                                 \
01254            {                                                                \
01255               (head_ptr) = (entry_ptr)->next;                               \
01256               if ( (head_ptr) != NULL )                                     \
01257               {                                                             \
01258                  (head_ptr)->prev = NULL;                                   \
01259               }                                                             \
01260            }                                                                \
01261            else                                                             \
01262            {                                                                \
01263               (entry_ptr)->prev->next = (entry_ptr)->next;                  \
01264            }                                                                \
01265            if ( (tail_ptr) == (entry_ptr) )                                 \
01266            {                                                                \
01267               (tail_ptr) = (entry_ptr)->prev;                               \
01268               if ( (tail_ptr) != NULL )                                     \
01269               {                                                             \
01270                  (tail_ptr)->next = NULL;                                   \
01271               }                                                             \
01272            }                                                                \
01273            else                                                             \
01274            {                                                                \
01275               (entry_ptr)->next->prev = (entry_ptr)->prev;                  \
01276            }                                                                \
01277            entry_ptr->next = NULL;                                          \
01278            entry_ptr->prev = NULL;                                          \
01279            (len)--;                                                         \
01280            (Size) -= entry_ptr->size;                                       \
01281         }
01282 
01283 #define H5C__DLL_UPDATE_FOR_SIZE_CHANGE(dll_len, dll_size, old_size, new_size) \
01284         H5C__DLL_PRE_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)     \
01285         (dll_size) -= (old_size);                                              \
01286         (dll_size) += (new_size);                                              \
01287         H5C__DLL_POST_SIZE_UPDATE_SC(dll_len, dll_size, old_size, new_size)
01288 
01289 #if H5C_DO_SANITY_CHECKS
01290 
01291 #define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
01292 if ( ( (hd_ptr) == NULL ) ||                                                   \
01293      ( (tail_ptr) == NULL ) ||                                                 \
01294      ( (entry_ptr) == NULL ) ||                                                \
01295      ( (len) <= 0 ) ||                                                         \
01296      ( (Size) < (entry_ptr)->size ) ||                                         \
01297      ( ( (Size) == (entry_ptr)->size ) && ( ! ( (len) == 1 ) ) ) ||            \
01298      ( ( (entry_ptr)->aux_prev == NULL ) && ( (hd_ptr) != (entry_ptr) ) ) ||   \
01299      ( ( (entry_ptr)->aux_next == NULL ) && ( (tail_ptr) != (entry_ptr) ) ) || \
01300      ( ( (len) == 1 ) &&                                                       \
01301        ( ! ( ( (hd_ptr) == (entry_ptr) ) && ( (tail_ptr) == (entry_ptr) ) &&   \
01302              ( (entry_ptr)->aux_next == NULL ) &&                              \
01303              ( (entry_ptr)->aux_prev == NULL ) &&                              \
01304              ( (Size) == (entry_ptr)->size )                                   \
01305            )                                                                   \
01306        )                                                                       \
01307      )                                                                         \
01308    ) {                                                                         \
01309     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "aux DLL pre remove SC failed")   \
01310 }
01311 
01312 #define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv)                  \
01313 if ( ( ( ( (head_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) &&              \
01314        ( (head_ptr) != (tail_ptr) )                                         \
01315      ) ||                                                                   \
01316      ( (len) < 0 ) ||                                                       \
01317      ( (Size) < 0 ) ||                                                      \
01318      ( ( (len) == 1 ) &&                                                    \
01319        ( ( (head_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) ||                 \
01320          ( (head_ptr) == NULL ) || ( (head_ptr)->size != (Size) )           \
01321        )                                                                    \
01322      ) ||                                                                   \
01323      ( ( (len) >= 1 ) &&                                                    \
01324        ( ( (head_ptr) == NULL ) || ( (head_ptr)->aux_prev != NULL ) ||      \
01325          ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL )         \
01326        )                                                                    \
01327      )                                                                      \
01328    ) {                                                                      \
01329     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL sanity check failed") \
01330 }
01331 
01332 #define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv) \
01333 if ( ( (entry_ptr) == NULL ) ||                                                \
01334      ( (entry_ptr)->aux_next != NULL ) ||                                      \
01335      ( (entry_ptr)->aux_prev != NULL ) ||                                      \
01336      ( ( ( (hd_ptr) == NULL ) || ( (tail_ptr) == NULL ) ) &&                   \
01337        ( (hd_ptr) != (tail_ptr) )                                              \
01338      ) ||                                                                      \
01339      ( (len) < 0 ) ||                                                          \
01340      ( ( (len) == 1 ) &&                                                       \
01341        ( ( (hd_ptr) != (tail_ptr) ) || ( (Size) <= 0 ) ||                      \
01342          ( (hd_ptr) == NULL ) || ( (hd_ptr)->size != (Size) )                  \
01343        )                                                                       \
01344      ) ||                                                                      \
01345      ( ( (len) >= 1 ) &&                                                       \
01346        ( ( (hd_ptr) == NULL ) || ( (hd_ptr)->aux_prev != NULL ) ||             \
01347          ( (tail_ptr) == NULL ) || ( (tail_ptr)->aux_next != NULL )            \
01348        )                                                                       \
01349      )                                                                         \
01350    ) {                                                                         \
01351     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, (fv), "AUX DLL pre insert SC failed")   \
01352 }
01353 
01354 #else /* H5C_DO_SANITY_CHECKS */
01355 
01356 #define H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
01357 #define H5C__AUX_DLL_SC(head_ptr, tail_ptr, len, Size, fv)
01358 #define H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, hd_ptr, tail_ptr, len, Size, fv)
01359 
01360 #endif /* H5C_DO_SANITY_CHECKS */
01361 
01362 
01363 #define H5C__AUX_DLL_APPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fail_val)\
01364         H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size,   \
01365                                    fail_val)                                   \
01366         if ( (head_ptr) == NULL )                                              \
01367         {                                                                      \
01368            (head_ptr) = (entry_ptr);                                           \
01369            (tail_ptr) = (entry_ptr);                                           \
01370         }                                                                      \
01371         else                                                                   \
01372         {                                                                      \
01373            (tail_ptr)->aux_next = (entry_ptr);                                 \
01374            (entry_ptr)->aux_prev = (tail_ptr);                                 \
01375            (tail_ptr) = (entry_ptr);                                           \
01376         }                                                                      \
01377         (len)++;                                                               \
01378         (Size) += entry_ptr->size;
01379 
01380 #define H5C__AUX_DLL_PREPEND(entry_ptr, head_ptr, tail_ptr, len, Size, fv)   \
01381         H5C__AUX_DLL_PRE_INSERT_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
01382                                    fv)                                       \
01383         if ( (head_ptr) == NULL )                                            \
01384         {                                                                    \
01385            (head_ptr) = (entry_ptr);                                         \
01386            (tail_ptr) = (entry_ptr);                                         \
01387         }                                                                    \
01388         else                                                                 \
01389         {                                                                    \
01390            (head_ptr)->aux_prev = (entry_ptr);                               \
01391            (entry_ptr)->aux_next = (head_ptr);                               \
01392            (head_ptr) = (entry_ptr);                                         \
01393         }                                                                    \
01394         (len)++;                                                             \
01395         (Size) += entry_ptr->size;
01396 
01397 #define H5C__AUX_DLL_REMOVE(entry_ptr, head_ptr, tail_ptr, len, Size, fv)    \
01398         H5C__AUX_DLL_PRE_REMOVE_SC(entry_ptr, head_ptr, tail_ptr, len, Size, \
01399                                    fv)                                       \
01400         {                                                                    \
01401            if ( (head_ptr) == (entry_ptr) )                                  \
01402            {                                                                 \
01403               (head_ptr) = (entry_ptr)->aux_next;                            \
01404               if ( (head_ptr) != NULL )                                      \
01405               {                                                              \
01406                  (head_ptr)->aux_prev = NULL;                                \
01407               }                                                              \
01408            }                                                                 \
01409            else                                                              \
01410            {                                                                 \
01411               (entry_ptr)->aux_prev->aux_next = (entry_ptr)->aux_next;       \
01412            }                                                                 \
01413            if ( (tail_ptr) == (entry_ptr) )                                  \
01414            {                                                                 \
01415               (tail_ptr) = (entry_ptr)->aux_prev;                            \
01416               if ( (tail_ptr) != NULL )                                      \
01417               {                                                              \
01418                  (tail_ptr)->aux_next = NULL;                                \
01419               }                                                              \
01420            }                                                                 \
01421            else                                                              \
01422            {                                                                 \
01423               (entry_ptr)->aux_next->aux_prev = (entry_ptr)->aux_prev;       \
01424            }                                                                 \
01425            entry_ptr->aux_next = NULL;                                       \
01426            entry_ptr->aux_prev = NULL;                                       \
01427            (len)--;                                                          \
01428            (Size) -= entry_ptr->size;                                        \
01429         }
01430 
01431 
01432 /***********************************************************************
01433  *
01434  * Stats collection macros
01435  *
01436  * The following macros must handle stats collection when this collection
01437  * is enabled, and evaluate to the empty string when it is not.
01438  *
01439  * The sole exception to this rule is
01440  * H5C__UPDATE_CACHE_HIT_RATE_STATS(), which is always active as
01441  * the cache hit rate stats are always collected and available.
01442  *
01443  * Changes:
01444  *
01445  *      JRM -- 3/21/06
01446  *      Added / updated macros for pinned entry related stats.
01447  *
01448  *      JRM -- 8/9/06
01449  *      More pinned entry stats related updates.
01450  *
01451  *      JRM -- 3/31/07
01452  *      Updated H5C__UPDATE_STATS_FOR_PROTECT() to keep stats on
01453  *      read and write protects.
01454  *
01455  *      MAM -- 1/15/09
01456  *      Created H5C__UPDATE_MAX_INDEX_SIZE_STATS to contain
01457  *      common code within macros that update the maximum
01458  *      index, clean_index, and dirty_index statistics fields.
01459  *
01460  ***********************************************************************/
01461 
01462 #define H5C__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit) \
01463         (cache_ptr->cache_accesses)++;                   \
01464         if ( hit ) {                                     \
01465             (cache_ptr->cache_hits)++;                   \
01466         }                                                \
01467 
01468 #if H5C_COLLECT_CACHE_STATS
01469 
01470 #define H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                        \
01471         if ( (cache_ptr)->index_size > (cache_ptr)->max_index_size )       \
01472             (cache_ptr)->max_index_size = (cache_ptr)->index_size;         \
01473         if ( (cache_ptr)->clean_index_size >                               \
01474                 (cache_ptr)->max_clean_index_size )                        \
01475             (cache_ptr)->max_clean_index_size =                            \
01476                 (cache_ptr)->clean_index_size;                             \
01477         if ( (cache_ptr)->dirty_index_size >                               \
01478                 (cache_ptr)->max_dirty_index_size )                        \
01479             (cache_ptr)->max_dirty_index_size =                            \
01480                 (cache_ptr)->dirty_index_size;
01481 
01482 #define H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) \
01483         (((cache_ptr)->dirty_pins)[(entry_ptr)->type->id])++;
01484 
01485 #define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)                   \
01486         if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len )   \
01487             (cache_ptr)->max_slist_len = (cache_ptr)->slist_len;     \
01488         if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size ) \
01489             (cache_ptr)->max_slist_size = (cache_ptr)->slist_size;   \
01490         if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len )       \
01491             (cache_ptr)->max_pel_len = (cache_ptr)->pel_len;         \
01492         if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size )     \
01493             (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;
01494 
01495 #define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr)               \
01496         if ( cache_ptr->flush_in_progress ) {                            \
01497             ((cache_ptr)->cache_flush_renames[(entry_ptr)->type->id])++; \
01498         }                                                                \
01499         if ( entry_ptr->flush_in_progress ) {                            \
01500             ((cache_ptr)->entry_flush_renames[(entry_ptr)->type->id])++; \
01501         }                                                                \
01502         (((cache_ptr)->renames)[(entry_ptr)->type->id])++;
01503 
01504 #define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)\
01505         if ( cache_ptr->flush_in_progress ) {                                  \
01506             ((cache_ptr)->cache_flush_size_changes[(entry_ptr)->type->id])++;  \
01507         }                                                                      \
01508         if ( entry_ptr->flush_in_progress ) {                                  \
01509             ((cache_ptr)->entry_flush_size_changes[(entry_ptr)->type->id])++;  \
01510         }                                                                      \
01511         if ( (entry_ptr)->size < (new_size) ) {                                \
01512             ((cache_ptr)->size_increases[(entry_ptr)->type->id])++;            \
01513             H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                        \
01514             if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size )       \
01515                 (cache_ptr)->max_slist_size = (cache_ptr)->slist_size;         \
01516             if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size )             \
01517                 (cache_ptr)->max_pl_size = (cache_ptr)->pl_size;               \
01518         } else if ( (entry_ptr)->size > (new_size) ) {                         \
01519             ((cache_ptr)->size_decreases[(entry_ptr)->type->id])++;            \
01520         }
01521 
01522 #define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr) \
01523         (cache_ptr)->total_ht_insertions++;
01524 
01525 #define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr) \
01526         (cache_ptr)->total_ht_deletions++;
01527 
01528 #define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth)  \
01529         if ( success ) {                                            \
01530             (cache_ptr)->successful_ht_searches++;                  \
01531             (cache_ptr)->total_successful_ht_search_depth += depth; \
01532         } else {                                                    \
01533             (cache_ptr)->failed_ht_searches++;                      \
01534             (cache_ptr)->total_failed_ht_search_depth += depth;     \
01535         }
01536 
01537 #define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) \
01538         ((cache_ptr)->unpins)[(entry_ptr)->type->id]++;
01539 
01540 #if H5C_COLLECT_CACHE_ENTRY_STATS
01541 
01542 #define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr) \
01543         (entry_ptr)->accesses = 0;              \
01544         (entry_ptr)->clears   = 0;              \
01545         (entry_ptr)->flushes  = 0;              \
01546         (entry_ptr)->pins     = 0;
01547 
01548 #define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)            \
01549         (((cache_ptr)->clears)[(entry_ptr)->type->id])++;            \
01550         if ( (entry_ptr)->is_pinned ) {                              \
01551             (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++; \
01552         }                                                            \
01553         ((entry_ptr)->clears)++;
01554 
01555 #define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)             \
01556         (((cache_ptr)->flushes)[(entry_ptr)->type->id])++;            \
01557         if ( (entry_ptr)->is_pinned ) {                               \
01558             (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \
01559         }                                                             \
01560         ((entry_ptr)->flushes)++;
01561 
01562 #define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr)        \
01563         (((cache_ptr)->evictions)[(entry_ptr)->type->id])++;        \
01564         if ( (entry_ptr)->accesses >                                \
01565              ((cache_ptr)->max_accesses)[(entry_ptr)->type->id] ) { \
01566             ((cache_ptr)->max_accesses)[(entry_ptr)->type->id]      \
01567                 = (entry_ptr)->accesses;                            \
01568         }                                                           \
01569         if ( (entry_ptr)->accesses <                                \
01570              ((cache_ptr)->min_accesses)[(entry_ptr)->type->id] ) { \
01571             ((cache_ptr)->min_accesses)[(entry_ptr)->type->id]      \
01572                 = (entry_ptr)->accesses;                            \
01573         }                                                           \
01574         if ( (entry_ptr)->clears >                                  \
01575              ((cache_ptr)->max_clears)[(entry_ptr)->type->id] ) {   \
01576             ((cache_ptr)->max_clears)[(entry_ptr)->type->id]        \
01577                  = (entry_ptr)->clears;                             \
01578         }                                                           \
01579         if ( (entry_ptr)->flushes >                                 \
01580              ((cache_ptr)->max_flushes)[(entry_ptr)->type->id] ) {  \
01581             ((cache_ptr)->max_flushes)[(entry_ptr)->type->id]       \
01582                  = (entry_ptr)->flushes;                            \
01583         }                                                           \
01584         if ( (entry_ptr)->size >                                    \
01585              ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) {     \
01586             ((cache_ptr)->max_size)[(entry_ptr)->type->id]          \
01587                  = (entry_ptr)->size;                               \
01588         }                                                           \
01589         if ( (entry_ptr)->pins >                                    \
01590              ((cache_ptr)->max_pins)[(entry_ptr)->type->id] ) {     \
01591             ((cache_ptr)->max_pins)[(entry_ptr)->type->id]          \
01592                  = (entry_ptr)->pins;                               \
01593         }
01594 
01595 #define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)            \
01596         (((cache_ptr)->insertions)[(entry_ptr)->type->id])++;            \
01597         if ( (entry_ptr)->is_pinned ) {                                  \
01598             (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \
01599             ((cache_ptr)->pins)[(entry_ptr)->type->id]++;                \
01600             (entry_ptr)->pins++;                                         \
01601             if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len )       \
01602                 (cache_ptr)->max_pel_len = (cache_ptr)->pel_len;         \
01603             if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size )     \
01604                 (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;       \
01605         }                                                                \
01606         if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len )       \
01607             (cache_ptr)->max_index_len = (cache_ptr)->index_len;         \
01608         H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                      \
01609         if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len )       \
01610             (cache_ptr)->max_slist_len = (cache_ptr)->slist_len;         \
01611         if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size )     \
01612             (cache_ptr)->max_slist_size = (cache_ptr)->slist_size;       \
01613         if ( (entry_ptr)->size >                                         \
01614              ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) {          \
01615             ((cache_ptr)->max_size)[(entry_ptr)->type->id]               \
01616                  = (entry_ptr)->size;                                    \
01617         }
01618 
01619 #define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)             \
01620         if ( hit )                                                           \
01621             ((cache_ptr)->hits)[(entry_ptr)->type->id]++;                    \
01622         else                                                                 \
01623             ((cache_ptr)->misses)[(entry_ptr)->type->id]++;                  \
01624         if ( ! ((entry_ptr)->is_read_only) ) {                               \
01625             ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++;          \
01626         } else {                                                             \
01627             ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++;           \
01628             if ( ((entry_ptr)->ro_ref_count) >                               \
01629                  ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \
01630                 ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] =    \
01631                         ((entry_ptr)->ro_ref_count);                         \
01632             }                                                                \
01633         }                                                                    \
01634         if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len )           \
01635             (cache_ptr)->max_index_len = (cache_ptr)->index_len;             \
01636         H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                          \
01637         if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len )                 \
01638             (cache_ptr)->max_pl_len = (cache_ptr)->pl_len;                   \
01639         if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size )               \
01640             (cache_ptr)->max_pl_size = (cache_ptr)->pl_size;                 \
01641         if ( (entry_ptr)->size >                                             \
01642              ((cache_ptr)->max_size)[(entry_ptr)->type->id] ) {              \
01643             ((cache_ptr)->max_size)[(entry_ptr)->type->id]                   \
01644                  = (entry_ptr)->size;                                        \
01645         }                                                                    \
01646         ((entry_ptr)->accesses)++;
01647 
01648 #define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr)          \
01649         ((cache_ptr)->pins)[(entry_ptr)->type->id]++;            \
01650         (entry_ptr)->pins++;                                     \
01651         if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len )   \
01652             (cache_ptr)->max_pel_len = (cache_ptr)->pel_len;     \
01653         if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
01654             (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;
01655 
01656 #else /* H5C_COLLECT_CACHE_ENTRY_STATS */
01657 
01658 #define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
01659 
01660 #define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)             \
01661         if ( (entry_ptr)->is_pinned ) {                               \
01662             (((cache_ptr)->pinned_clears)[(entry_ptr)->type->id])++;  \
01663         }                                                             \
01664         (((cache_ptr)->clears)[(entry_ptr)->type->id])++;
01665 
01666 #define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)             \
01667         (((cache_ptr)->flushes)[(entry_ptr)->type->id])++;            \
01668         if ( (entry_ptr)->is_pinned ) {                               \
01669             (((cache_ptr)->pinned_flushes)[(entry_ptr)->type->id])++; \
01670         }
01671 
01672 #define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr) \
01673         (((cache_ptr)->evictions)[(entry_ptr)->type->id])++;
01674 
01675 #define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)            \
01676         (((cache_ptr)->insertions)[(entry_ptr)->type->id])++;            \
01677         if ( (entry_ptr)->is_pinned ) {                                  \
01678             (((cache_ptr)->pinned_insertions)[(entry_ptr)->type->id])++; \
01679             ((cache_ptr)->pins)[(entry_ptr)->type->id]++;                \
01680             if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len )       \
01681                 (cache_ptr)->max_pel_len = (cache_ptr)->pel_len;         \
01682             if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size )     \
01683                 (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;       \
01684         }                                                                \
01685         if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len )       \
01686             (cache_ptr)->max_index_len = (cache_ptr)->index_len;         \
01687         H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                      \
01688         if ( (cache_ptr)->slist_len > (cache_ptr)->max_slist_len )       \
01689             (cache_ptr)->max_slist_len = (cache_ptr)->slist_len;         \
01690         if ( (cache_ptr)->slist_size > (cache_ptr)->max_slist_size )     \
01691             (cache_ptr)->max_slist_size = (cache_ptr)->slist_size;
01692 
01693 #define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)             \
01694         if ( hit )                                                           \
01695             ((cache_ptr)->hits)[(entry_ptr)->type->id]++;                    \
01696         else                                                                 \
01697             ((cache_ptr)->misses)[(entry_ptr)->type->id]++;                  \
01698         if ( ! ((entry_ptr)->is_read_only) ) {                               \
01699             ((cache_ptr)->write_protects)[(entry_ptr)->type->id]++;          \
01700         } else {                                                             \
01701             ((cache_ptr)->read_protects)[(entry_ptr)->type->id]++;           \
01702             if ( ((entry_ptr)->ro_ref_count) >                               \
01703                  ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] ) { \
01704                 ((cache_ptr)->max_read_protects)[(entry_ptr)->type->id] =    \
01705                         ((entry_ptr)->ro_ref_count);                         \
01706             }                                                                \
01707         }                                                                    \
01708         if ( (cache_ptr)->index_len > (cache_ptr)->max_index_len )           \
01709             (cache_ptr)->max_index_len = (cache_ptr)->index_len;             \
01710         H5C__UPDATE_MAX_INDEX_SIZE_STATS(cache_ptr)                          \
01711         if ( (cache_ptr)->pl_len > (cache_ptr)->max_pl_len )                 \
01712             (cache_ptr)->max_pl_len = (cache_ptr)->pl_len;                   \
01713         if ( (cache_ptr)->pl_size > (cache_ptr)->max_pl_size )               \
01714             (cache_ptr)->max_pl_size = (cache_ptr)->pl_size;
01715 
01716 #define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr)          \
01717         ((cache_ptr)->pins)[(entry_ptr)->type->id]++;            \
01718         if ( (cache_ptr)->pel_len > (cache_ptr)->max_pel_len )   \
01719             (cache_ptr)->max_pel_len = (cache_ptr)->pel_len;     \
01720         if ( (cache_ptr)->pel_size > (cache_ptr)->max_pel_size ) \
01721             (cache_ptr)->max_pel_size = (cache_ptr)->pel_size;
01722 
01723 #endif /* H5C_COLLECT_CACHE_ENTRY_STATS */
01724 
01725 #else /* H5C_COLLECT_CACHE_STATS */
01726 
01727 #define H5C__RESET_CACHE_ENTRY_STATS(entry_ptr)
01728 #define H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr)
01729 #define H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr)
01730 #define H5C__UPDATE_STATS_FOR_RENAME(cache_ptr, entry_ptr)
01731 #define H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)
01732 #define H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr)
01733 #define H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr)
01734 #define H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, success, depth)
01735 #define H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr)
01736 #define H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr)
01737 #define H5C__UPDATE_STATS_FOR_FLUSH(cache_ptr, entry_ptr)
01738 #define H5C__UPDATE_STATS_FOR_EVICTION(cache_ptr, entry_ptr)
01739 #define H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit)
01740 #define H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr)
01741 #define H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr)
01742 
01743 #endif /* H5C_COLLECT_CACHE_STATS */
01744 
01745 
01746 /***********************************************************************
01747  *
01748  * Hash table access and manipulation macros:
01749  *
01750  * The following macros handle searches, insertions, and deletion in
01751  * the hash table.
01752  *
01753  * When modifying these macros, remember to modify the similar macros
01754  * in tst/cache.c
01755  *
01756  * Changes:
01757  *
01758  *   - Updated existing index macros and sanity check macros to maintain
01759  *     the clean_index_size and dirty_index_size fields of H5C_t.  Also
01760  *     added macros to allow us to track entry cleans and dirties.
01761  *
01762  *                                              JRM -- 11/5/08
01763  *
01764  ***********************************************************************/
01765 
01766 /* H5C__HASH_TABLE_LEN is defined in H5Cpkg.h.  It mut be a power of two. */
01767 
01768 #define H5C__HASH_MASK          ((size_t)(H5C__HASH_TABLE_LEN - 1) << 3)
01769 
01770 #define H5C__HASH_FCN(x)        (int)(((x) & H5C__HASH_MASK) >> 3)
01771 
01772 #if H5C_DO_SANITY_CHECKS
01773 
01774 #define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val) \
01775 if ( ( (cache_ptr) == NULL ) ||                               \
01776      ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||            \
01777      ( (entry_ptr) == NULL ) ||                               \
01778      ( ! H5F_addr_defined((entry_ptr)->addr) ) ||             \
01779      ( (entry_ptr)->ht_next != NULL ) ||                      \
01780      ( (entry_ptr)->ht_prev != NULL ) ||                      \
01781      ( (entry_ptr)->size <= 0 ) ||                            \
01782      ( (k = H5C__HASH_FCN((entry_ptr)->addr)) < 0 ) ||        \
01783      ( k >= H5C__HASH_TABLE_LEN ) ||                          \
01784      ( (cache_ptr)->index_size !=                             \
01785        ((cache_ptr)->clean_index_size +                       \
01786         (cache_ptr)->dirty_index_size) ) ) {                  \
01787     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val,              \
01788                "Pre HT insert SC failed")                     \
01789 }
01790 
01791 #define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr)                     \
01792 if ( ( (cache_ptr) == NULL ) ||                                         \
01793      ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||                      \
01794      ( (cache_ptr)->index_len < 1 ) ||                                  \
01795      ( (entry_ptr) == NULL ) ||                                         \
01796      ( (cache_ptr)->index_size < (entry_ptr)->size ) ||                 \
01797      ( ! H5F_addr_defined((entry_ptr)->addr) ) ||                       \
01798      ( (entry_ptr)->size <= 0 ) ||                                      \
01799      ( H5C__HASH_FCN((entry_ptr)->addr) < 0 ) ||                        \
01800      ( H5C__HASH_FCN((entry_ptr)->addr) >= H5C__HASH_TABLE_LEN ) ||     \
01801      ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))]         \
01802        == NULL ) ||                                                     \
01803      ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))]       \
01804        != (entry_ptr) ) &&                                              \
01805        ( (entry_ptr)->ht_prev == NULL ) ) ||                            \
01806      ( ( ((cache_ptr)->index)[(H5C__HASH_FCN((entry_ptr)->addr))] ==    \
01807          (entry_ptr) ) &&                                               \
01808        ( (entry_ptr)->ht_prev != NULL ) ) ||                            \
01809      ( (cache_ptr)->index_size !=                                       \
01810        ((cache_ptr)->clean_index_size +                                 \
01811         (cache_ptr)->dirty_index_size) ) ) {                            \
01812     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Pre HT remove SC failed") \
01813 }
01814 
01815 /* (Keep in sync w/H5C_TEST__PRE_HT_SEARCH_SC macro in test/cache_common.h -QAK) */
01816 #define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)                    \
01817 if ( ( (cache_ptr) == NULL ) ||                                             \
01818      ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||                          \
01819      ( (cache_ptr)->index_size !=                                           \
01820        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
01821      ( ! H5F_addr_defined(Addr) ) ||                                        \
01822      ( H5C__HASH_FCN(Addr) < 0 ) ||                                         \
01823      ( H5C__HASH_FCN(Addr) >= H5C__HASH_TABLE_LEN ) ) {                     \
01824     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val, "Pre HT search SC failed") \
01825 }
01826 
01827 /* (Keep in sync w/H5C_TEST__POST_SUC_HT_SEARCH_SC macro in test/cache_common.h -QAK) */
01828 #define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \
01829 if ( ( (cache_ptr) == NULL ) ||                                             \
01830      ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||                          \
01831      ( (cache_ptr)->index_len < 1 ) ||                                      \
01832      ( (entry_ptr) == NULL ) ||                                             \
01833      ( (cache_ptr)->index_size < (entry_ptr)->size ) ||                     \
01834      ( (cache_ptr)->index_size !=                                           \
01835        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) || \
01836      ( H5F_addr_ne((entry_ptr)->addr, (Addr)) ) ||                          \
01837      ( (entry_ptr)->size <= 0 ) ||                                          \
01838      ( ((cache_ptr)->index)[k] == NULL ) ||                                 \
01839      ( ( ((cache_ptr)->index)[k] != (entry_ptr) ) &&                        \
01840        ( (entry_ptr)->ht_prev == NULL ) ) ||                                \
01841      ( ( ((cache_ptr)->index)[k] == (entry_ptr) ) &&                        \
01842        ( (entry_ptr)->ht_prev != NULL ) ) ||                                \
01843      ( ( (entry_ptr)->ht_prev != NULL ) &&                                  \
01844        ( (entry_ptr)->ht_prev->ht_next != (entry_ptr) ) ) ||                \
01845      ( ( (entry_ptr)->ht_next != NULL ) &&                                  \
01846        ( (entry_ptr)->ht_next->ht_prev != (entry_ptr) ) ) ) {               \
01847     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val,                            \
01848                 "Post successful HT search SC failed")                      \
01849 }
01850 
01851 /* (Keep in sync w/H5C_TEST__POST_HT_SHIFT_TO_FRONT macro in test/cache_common.h -QAK) */
01852 #define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val) \
01853 if ( ( (cache_ptr) == NULL ) ||                                        \
01854      ( ((cache_ptr)->index)[k] != (entry_ptr) ) ||                     \
01855      ( (entry_ptr)->ht_prev != NULL ) ) {                              \
01856     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, fail_val,                       \
01857                 "Post HT shift to front SC failed")                    \
01858 }
01859 
01860 #define H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
01861                                          entry_ptr, was_clean)          \
01862 if ( ( (cache_ptr) == NULL ) ||                                         \
01863      ( (cache_ptr)->index_len <= 0 ) ||                                 \
01864      ( (cache_ptr)->index_size <= 0 ) ||                                \
01865      ( (new_size) <= 0 ) ||                                             \
01866      ( (old_size) > (cache_ptr)->index_size ) ||                        \
01867      ( (new_size) <= 0 ) ||                                             \
01868      ( ( (cache_ptr)->index_len == 1 ) &&                               \
01869        ( (cache_ptr)->index_size != (old_size) ) ) ||                   \
01870      ( (cache_ptr)->index_size !=                                       \
01871        ((cache_ptr)->clean_index_size +                                 \
01872         (cache_ptr)->dirty_index_size) ) ||                             \
01873      ( (entry_ptr == NULL) ) ||                                         \
01874      ( ( !( was_clean ) ||                                              \
01875             ( (cache_ptr)->clean_index_size < (old_size) ) ) &&         \
01876           ( ( (was_clean) ) ||                                          \
01877             ( (cache_ptr)->dirty_index_size < (old_size) ) ) )          \
01878      ( (entry_ptr) == NULL ) ) {                                        \
01879     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                            \
01880                 "Pre HT entry size change SC failed")                   \
01881 }
01882 
01883 #define H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size,  \
01884                                           entry_ptr)                      \
01885 if ( ( (cache_ptr) == NULL ) ||                                           \
01886      ( (cache_ptr)->index_len <= 0 ) ||                                   \
01887      ( (cache_ptr)->index_size <= 0 ) ||                                  \
01888      ( (new_size) > (cache_ptr)->index_size ) ||                          \
01889      ( (cache_ptr)->index_size !=                                         \
01890           ((cache_ptr)->clean_index_size +                                \
01891            (cache_ptr)->dirty_index_size) ) ||                            \
01892      ( ( !((entry_ptr)->is_dirty ) ||                                     \
01893             ( (cache_ptr)->dirty_index_size < (new_size) ) ) &&           \
01894           ( ( ((entry_ptr)->is_dirty)  ) ||                               \
01895             ( (cache_ptr)->clean_index_size < (new_size) ) ) )            \
01896      ( ( (cache_ptr)->index_len == 1 ) &&                                 \
01897        ( (cache_ptr)->index_size != (new_size) ) ) ) {                    \
01898     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                              \
01899                 "Post HT entry size change SC failed")                    \
01900 }
01901 
01902 #define H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)           \
01903 if (                                                                          \
01904     ( (cache_ptr) == NULL ) ||                                                \
01905     ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||                             \
01906     ( (cache_ptr)->index_len <= 0 ) ||                                        \
01907     ( (entry_ptr) == NULL ) ||                                                \
01908     ( (entry_ptr)->is_dirty != FALSE ) ||                                     \
01909     ( (cache_ptr)->index_size < (entry_ptr)->size ) ||                        \
01910     ( (cache_ptr)->dirty_index_size < (entry_ptr)->size ) ||                  \
01911     ( (cache_ptr)->index_size !=                                              \
01912        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) ) {  \
01913     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                                  \
01914                 "Pre HT update for entry clean SC failed")                    \
01915 }
01916 
01917 #define H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)           \
01918 if (                                                                          \
01919     ( (cache_ptr) == NULL ) ||                                                \
01920     ( (cache_ptr)->magic != H5C__H5C_T_MAGIC ) ||                             \
01921     ( (cache_ptr)->index_len <= 0 ) ||                                        \
01922     ( (entry_ptr) == NULL ) ||                                                \
01923     ( (entry_ptr)->is_dirty != TRUE ) ||                                      \
01924     ( (cache_ptr)->index_size < (entry_ptr)->size ) ||                        \
01925     ( (cache_ptr)->clean_index_size < (entry_ptr)->size ) ||                  \
01926     ( (cache_ptr)->index_size !=                                              \
01927        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) ) {  \
01928     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                                  \
01929                 "Pre HT update for entry dirty SC failed")                    \
01930 }
01931 
01932 #define H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)        \
01933 if ( (cache_ptr)->index_size !=                                             \
01934        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) {  \
01935     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                                \
01936                 "Post HT update for entry clean SC failed")                 \
01937 }
01938 
01939 #define H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)        \
01940 if ( (cache_ptr)->index_size !=                                             \
01941        ((cache_ptr)->clean_index_size + (cache_ptr)->dirty_index_size) ) {  \
01942     HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL,                                \
01943                 "Post HT update for entry dirty SC failed")                 \
01944 }
01945 
01946 #else /* H5C_DO_SANITY_CHECKS */
01947 
01948 #define H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val)
01949 #define H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr)
01950 #define H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)
01951 #define H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val)
01952 #define H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val)
01953 #define H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)
01954 #define H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)
01955 #define H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
01956                                          entry_ptr, was_clean)
01957 #define H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, \
01958                                           entry_ptr)
01959 #define H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr)
01960 #define H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr)
01961 
01962 #endif /* H5C_DO_SANITY_CHECKS */
01963 
01964 
01965 #define H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, fail_val) \
01966 {                                                            \
01967     int k;                                                   \
01968     H5C__PRE_HT_INSERT_SC(cache_ptr, entry_ptr, fail_val)    \
01969     k = H5C__HASH_FCN((entry_ptr)->addr);                    \
01970     if ( ((cache_ptr)->index)[k] == NULL )                   \
01971     {                                                        \
01972         ((cache_ptr)->index)[k] = (entry_ptr);               \
01973     }                                                        \
01974     else                                                     \
01975     {                                                        \
01976         (entry_ptr)->ht_next = ((cache_ptr)->index)[k];      \
01977         (entry_ptr)->ht_next->ht_prev = (entry_ptr);         \
01978         ((cache_ptr)->index)[k] = (entry_ptr);               \
01979     }                                                        \
01980     (cache_ptr)->index_len++;                                \
01981     (cache_ptr)->index_size += (entry_ptr)->size;            \
01982     if ( (entry_ptr)->is_dirty ) {                           \
01983         (cache_ptr)->dirty_index_size += (entry_ptr)->size;  \
01984     } else {                                                 \
01985         (cache_ptr)->clean_index_size += (entry_ptr)->size;  \
01986     }                                                        \
01987     H5C__UPDATE_STATS_FOR_HT_INSERTION(cache_ptr)            \
01988 }
01989 
01990 #define H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr)          \
01991 {                                                             \
01992     int k;                                                    \
01993     H5C__PRE_HT_REMOVE_SC(cache_ptr, entry_ptr)               \
01994     k = H5C__HASH_FCN((entry_ptr)->addr);                     \
01995     if ( (entry_ptr)->ht_next )                               \
01996     {                                                         \
01997         (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev; \
01998     }                                                         \
01999     if ( (entry_ptr)->ht_prev )                               \
02000     {                                                         \
02001         (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next; \
02002     }                                                         \
02003     if ( ((cache_ptr)->index)[k] == (entry_ptr) )             \
02004     {                                                         \
02005         ((cache_ptr)->index)[k] = (entry_ptr)->ht_next;       \
02006     }                                                         \
02007     (entry_ptr)->ht_next = NULL;                              \
02008     (entry_ptr)->ht_prev = NULL;                              \
02009     (cache_ptr)->index_len--;                                 \
02010     (cache_ptr)->index_size -= (entry_ptr)->size;             \
02011     if ( (entry_ptr)->is_dirty ) {                            \
02012         (cache_ptr)->dirty_index_size -= (entry_ptr)->size;   \
02013     } else {                                                  \
02014         (cache_ptr)->clean_index_size -= (entry_ptr)->size;   \
02015     }                                                         \
02016     H5C__UPDATE_STATS_FOR_HT_DELETION(cache_ptr)              \
02017 }
02018 
02019 #define H5C__SEARCH_INDEX(cache_ptr, Addr, entry_ptr, fail_val)             \
02020 {                                                                           \
02021     int k;                                                                  \
02022     int depth = 0;                                                          \
02023     H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)                        \
02024     k = H5C__HASH_FCN(Addr);                                                \
02025     entry_ptr = ((cache_ptr)->index)[k];                                    \
02026     while ( ( entry_ptr ) && ( H5F_addr_ne(Addr, (entry_ptr)->addr) ) )     \
02027     {                                                                       \
02028         (entry_ptr) = (entry_ptr)->ht_next;                                 \
02029         (depth)++;                                                          \
02030     }                                                                       \
02031     if ( entry_ptr )                                                        \
02032     {                                                                       \
02033         H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \
02034         if ( entry_ptr != ((cache_ptr)->index)[k] )                         \
02035         {                                                                   \
02036             if ( (entry_ptr)->ht_next )                                     \
02037             {                                                               \
02038                 (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev;       \
02039             }                                                               \
02040             HDassert( (entry_ptr)->ht_prev != NULL );                       \
02041             (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next;           \
02042             ((cache_ptr)->index)[k]->ht_prev = (entry_ptr);                 \
02043             (entry_ptr)->ht_next = ((cache_ptr)->index)[k];                 \
02044             (entry_ptr)->ht_prev = NULL;                                    \
02045             ((cache_ptr)->index)[k] = (entry_ptr);                          \
02046             H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val)  \
02047         }                                                                   \
02048     }                                                                       \
02049     H5C__UPDATE_STATS_FOR_HT_SEARCH(cache_ptr, (entry_ptr != NULL), depth)  \
02050 }
02051 
02052 #define H5C__SEARCH_INDEX_NO_STATS(cache_ptr, Addr, entry_ptr, fail_val)    \
02053 {                                                                           \
02054     int k;                                                                  \
02055     int depth = 0;                                                          \
02056     H5C__PRE_HT_SEARCH_SC(cache_ptr, Addr, fail_val)                        \
02057     k = H5C__HASH_FCN(Addr);                                                \
02058     entry_ptr = ((cache_ptr)->index)[k];                                    \
02059     while ( ( entry_ptr ) && ( H5F_addr_ne(Addr, (entry_ptr)->addr) ) )     \
02060     {                                                                       \
02061         (entry_ptr) = (entry_ptr)->ht_next;                                 \
02062         (depth)++;                                                          \
02063     }                                                                       \
02064     if ( entry_ptr )                                                        \
02065     {                                                                       \
02066         H5C__POST_SUC_HT_SEARCH_SC(cache_ptr, entry_ptr, Addr, k, fail_val) \
02067         if ( entry_ptr != ((cache_ptr)->index)[k] )                         \
02068         {                                                                   \
02069             if ( (entry_ptr)->ht_next )                                     \
02070             {                                                               \
02071                 (entry_ptr)->ht_next->ht_prev = (entry_ptr)->ht_prev;       \
02072             }                                                               \
02073             HDassert( (entry_ptr)->ht_prev != NULL );                       \
02074             (entry_ptr)->ht_prev->ht_next = (entry_ptr)->ht_next;           \
02075             ((cache_ptr)->index)[k]->ht_prev = (entry_ptr);                 \
02076             (entry_ptr)->ht_next = ((cache_ptr)->index)[k];                 \
02077             (entry_ptr)->ht_prev = NULL;                                    \
02078             ((cache_ptr)->index)[k] = (entry_ptr);                          \
02079             H5C__POST_HT_SHIFT_TO_FRONT(cache_ptr, entry_ptr, k, fail_val)  \
02080         }                                                                   \
02081     }                                                                       \
02082 }
02083 
02084 #define H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr)   \
02085 {                                                                 \
02086     H5C__PRE_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr);  \
02087     (cache_ptr)->dirty_index_size -= (entry_ptr)->size;           \
02088     (cache_ptr)->clean_index_size += (entry_ptr)->size;           \
02089     H5C__POST_HT_UPDATE_FOR_ENTRY_CLEAN_SC(cache_ptr, entry_ptr); \
02090 }
02091 
02092 #define H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr)   \
02093 {                                                                 \
02094     H5C__PRE_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr);  \
02095     (cache_ptr)->clean_index_size -= (entry_ptr)->size;           \
02096     (cache_ptr)->dirty_index_size += (entry_ptr)->size;           \
02097     H5C__POST_HT_UPDATE_FOR_ENTRY_DIRTY_SC(cache_ptr, entry_ptr); \
02098 }
02099 
02100 #define H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size,      \
02101                                           entry_ptr, was_clean)               \
02102 {                                                                             \
02103     H5C__PRE_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size,           \
02104                                      entry_ptr, was_clean)                    \
02105     (cache_ptr)->index_size -= (old_size);                                    \
02106     (cache_ptr)->index_size += (new_size);                                    \
02107     if ( was_clean ) {                                                        \
02108         (cache_ptr)->clean_index_size -= (old_size);                          \
02109     } else {                                                                  \
02110         (cache_ptr)->dirty_index_size -= (old_size);                          \
02111     }                                                                         \
02112     if ( (entry_ptr)->is_dirty ) {                                            \
02113         (cache_ptr)->dirty_index_size += (new_size);                          \
02114     } else {                                                                  \
02115         (cache_ptr)->clean_index_size += (new_size);                          \
02116     }                                                                         \
02117     H5C__POST_HT_ENTRY_SIZE_CHANGE_SC(cache_ptr, old_size, new_size, entry_ptr) \
02118 }
02119 
02120 
02121 /**************************************************************************
02122  *
02123  * Skip list insertion and deletion macros:
02124  *
02125  * These used to be functions, but I converted them to macros to avoid some
02126  * function call overhead.
02127  *
02128  **************************************************************************/
02129 
02130 /*-------------------------------------------------------------------------
02131  *
02132  * Macro:       H5C__INSERT_ENTRY_IN_SLIST
02133  *
02134  * Purpose:     Insert the specified instance of H5C_cache_entry_t into
02135  *              the skip list in the specified instance of H5C_t.  Update
02136  *              the associated length and size fields.
02137  *
02138  * Return:      N/A
02139  *
02140  * Programmer:  John Mainzer, 5/10/04
02141  *
02142  * Modifications:
02143  *
02144  *              JRM -- 7/21/04
02145  *              Updated function to set the in_tree flag when inserting
02146  *              an entry into the tree.  Also modified the function to
02147  *              update the tree size and len fields instead of the similar
02148  *              index fields.
02149  *
02150  *              All of this is part of the modifications to support the
02151  *              hash table.
02152  *
02153  *              JRM -- 7/27/04
02154  *              Converted the function H5C_insert_entry_in_tree() into
02155  *              the macro H5C__INSERT_ENTRY_IN_TREE in the hopes of
02156  *              wringing a little more speed out of the cache.
02157  *
02158  *              Note that we don't bother to check if the entry is already
02159  *              in the tree -- if it is, H5SL_insert() will fail.
02160  *
02161  *              QAK -- 11/27/04
02162  *              Switched over to using skip list routines.
02163  *
02164  *              JRM -- 6/27/06
02165  *              Added fail_val parameter.
02166  *
02167  *              JRM -- 8/25/06
02168  *              Added the H5C_DO_SANITY_CHECKS version of the macro.
02169  *
02170  *              This version maintains the slist_len_increase and
02171  *              slist_size_increase fields that are used in sanity
02172  *              checks in the flush routines.
02173  *
02174  *              All this is needed as the fractal heap needs to be
02175  *              able to dirty, resize and/or rename entries during the
02176  *              flush.
02177  *
02178  *-------------------------------------------------------------------------
02179  */
02180 
02181 #if H5C_DO_SANITY_CHECKS
02182 
02183 #define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val)             \
02184 {                                                                              \
02185     HDassert( (cache_ptr) );                                                   \
02186     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                        \
02187     HDassert( (entry_ptr) );                                                   \
02188     HDassert( (entry_ptr)->size > 0 );                                         \
02189     HDassert( H5F_addr_defined((entry_ptr)->addr) );                           \
02190     HDassert( !((entry_ptr)->in_slist) );                                      \
02191                                                                                \
02192     if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr)    \
02193                                                                          < 0 ) \
02194         HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val),                       \
02195                     "Can't insert entry in skip list")                         \
02196                                                                                \
02197     (entry_ptr)->in_slist = TRUE;                                              \
02198     (cache_ptr)->slist_len++;                                                  \
02199     (cache_ptr)->slist_size += (entry_ptr)->size;                              \
02200     (cache_ptr)->slist_len_increase++;                                         \
02201     (cache_ptr)->slist_size_increase += (entry_ptr)->size;                     \
02202                                                                                \
02203     HDassert( (cache_ptr)->slist_len > 0 );                                    \
02204     HDassert( (cache_ptr)->slist_size > 0 );                                   \
02205                                                                                \
02206 } /* H5C__INSERT_ENTRY_IN_SLIST */
02207 
02208 #else /* H5C_DO_SANITY_CHECKS */
02209 
02210 #define H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, fail_val)             \
02211 {                                                                              \
02212     HDassert( (cache_ptr) );                                                   \
02213     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                        \
02214     HDassert( (entry_ptr) );                                                   \
02215     HDassert( (entry_ptr)->size > 0 );                                         \
02216     HDassert( H5F_addr_defined((entry_ptr)->addr) );                           \
02217     HDassert( !((entry_ptr)->in_slist) );                                      \
02218                                                                                \
02219     if ( H5SL_insert((cache_ptr)->slist_ptr, entry_ptr, &(entry_ptr)->addr)    \
02220                                                                          < 0 ) \
02221         HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, (fail_val),                       \
02222                     "Can't insert entry in skip list")                         \
02223                                                                                \
02224     (entry_ptr)->in_slist = TRUE;                                              \
02225     (cache_ptr)->slist_len++;                                                  \
02226     (cache_ptr)->slist_size += (entry_ptr)->size;                              \
02227                                                                                \
02228     HDassert( (cache_ptr)->slist_len > 0 );                                    \
02229     HDassert( (cache_ptr)->slist_size > 0 );                                   \
02230                                                                                \
02231 } /* H5C__INSERT_ENTRY_IN_SLIST */
02232 
02233 #endif /* H5C_DO_SANITY_CHECKS */
02234 
02235 
02236 /*-------------------------------------------------------------------------
02237  *
02238  * Function:    H5C__REMOVE_ENTRY_FROM_SLIST
02239  *
02240  * Purpose:     Remove the specified instance of H5C_cache_entry_t from the
02241  *              index skip list in the specified instance of H5C_t.  Update
02242  *              the associated length and size fields.
02243  *
02244  * Return:      N/A
02245  *
02246  * Programmer:  John Mainzer, 5/10/04
02247  *
02248  * Modifications:
02249  *
02250  *              JRM -- 7/21/04
02251  *              Updated function for the addition of the hash table.
02252  *
02253  *              JRM - 7/27/04
02254  *              Converted from the function H5C_remove_entry_from_tree()
02255  *              to the macro H5C__REMOVE_ENTRY_FROM_TREE in the hopes of
02256  *              wringing a little more performance out of the cache.
02257  *
02258  *              QAK -- 11/27/04
02259  *              Switched over to using skip list routines.
02260  *
02261  *              JRM -- 3/28/07
02262  *              Updated sanity checks for the new is_read_only and
02263  *              ro_ref_count fields in H5C_cache_entry_t.
02264  *
02265  *-------------------------------------------------------------------------
02266  */
02267 
02268 #define H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr)          \
02269 {                                                                   \
02270     HDassert( (cache_ptr) );                                        \
02271     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );             \
02272     HDassert( (entry_ptr) );                                        \
02273     HDassert( !((entry_ptr)->is_protected) );                       \
02274     HDassert( !((entry_ptr)->is_read_only) );                       \
02275     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                   \
02276     HDassert( (entry_ptr)->size > 0 );                              \
02277     HDassert( (entry_ptr)->in_slist );                              \
02278     HDassert( (cache_ptr)->slist_ptr );                             \
02279                                                                     \
02280     if ( H5SL_remove((cache_ptr)->slist_ptr, &(entry_ptr)->addr)    \
02281          != (entry_ptr) )                                           \
02282                                                                     \
02283         HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL,                  \
02284                     "Can't delete entry from skip list.")           \
02285                                                                     \
02286     HDassert( (cache_ptr)->slist_len > 0 );                         \
02287     (cache_ptr)->slist_len--;                                       \
02288     HDassert( (cache_ptr)->slist_size >= (entry_ptr)->size );       \
02289     (cache_ptr)->slist_size -= (entry_ptr)->size;                   \
02290     (entry_ptr)->in_slist = FALSE;                                  \
02291 } /* H5C__REMOVE_ENTRY_FROM_SLIST */
02292 
02293 
02294 /*-------------------------------------------------------------------------
02295  *
02296  * Function:    H5C__UPDATE_SLIST_FOR_SIZE_CHANGE
02297  *
02298  * Purpose:     Update cache_ptr->slist_size for a change in the size of
02299  *              and entry in the slist.
02300  *
02301  * Return:      N/A
02302  *
02303  * Programmer:  John Mainzer, 9/07/05
02304  *
02305  * Modifications:
02306  *
02307  *              JRM -- 8/27/06
02308  *              Added the H5C_DO_SANITY_CHECKS version of the macro.
02309  *
02310  *              This version maintains the slist_size_increase field
02311  *              that are used in sanity checks in the flush routines.
02312  *
02313  *              All this is needed as the fractal heap needs to be
02314  *              able to dirty, resize and/or rename entries during the
02315  *              flush.
02316  *
02317  *-------------------------------------------------------------------------
02318  */
02319 
02320 #if H5C_DO_SANITY_CHECKS
02321 
02322 #define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \
02323 {                                                                        \
02324     HDassert( (cache_ptr) );                                             \
02325     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                  \
02326     HDassert( (old_size) > 0 );                                          \
02327     HDassert( (new_size) > 0 );                                          \
02328     HDassert( (old_size) <= (cache_ptr)->slist_size );                   \
02329     HDassert( (cache_ptr)->slist_len > 0 );                              \
02330     HDassert( ((cache_ptr)->slist_len > 1) ||                            \
02331               ( (cache_ptr)->slist_size == (old_size) ) );               \
02332                                                                          \
02333     (cache_ptr)->slist_size -= (old_size);                               \
02334     (cache_ptr)->slist_size += (new_size);                               \
02335                                                                          \
02336     (cache_ptr)->slist_size_increase -= (int64_t)(old_size);             \
02337     (cache_ptr)->slist_size_increase += (int64_t)(new_size);             \
02338                                                                          \
02339     HDassert( (new_size) <= (cache_ptr)->slist_size );                   \
02340     HDassert( ( (cache_ptr)->slist_len > 1 ) ||                          \
02341               ( (cache_ptr)->slist_size == (new_size) ) );               \
02342 } /* H5C__REMOVE_ENTRY_FROM_SLIST */
02343 
02344 #else /* H5C_DO_SANITY_CHECKS */
02345 
02346 #define H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, old_size, new_size) \
02347 {                                                                        \
02348     HDassert( (cache_ptr) );                                             \
02349     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                  \
02350     HDassert( (old_size) > 0 );                                          \
02351     HDassert( (new_size) > 0 );                                          \
02352     HDassert( (old_size) <= (cache_ptr)->slist_size );                   \
02353     HDassert( (cache_ptr)->slist_len > 0 );                              \
02354     HDassert( ((cache_ptr)->slist_len > 1) ||                            \
02355               ( (cache_ptr)->slist_size == (old_size) ) );               \
02356                                                                          \
02357     (cache_ptr)->slist_size -= (old_size);                               \
02358     (cache_ptr)->slist_size += (new_size);                               \
02359                                                                          \
02360     HDassert( (new_size) <= (cache_ptr)->slist_size );                   \
02361     HDassert( ( (cache_ptr)->slist_len > 1 ) ||                          \
02362               ( (cache_ptr)->slist_size == (new_size) ) );               \
02363 } /* H5C__REMOVE_ENTRY_FROM_SLIST */
02364 
02365 #endif /* H5C_DO_SANITY_CHECKS */
02366 
02367 
02368 /**************************************************************************
02369  *
02370  * Replacement policy update macros:
02371  *
02372  * These used to be functions, but I converted them to macros to avoid some
02373  * function call overhead.
02374  *
02375  **************************************************************************/
02376 
02377 /*-------------------------------------------------------------------------
02378  *
02379  * Macro:       H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS
02380  *
02381  * Purpose:     For efficiency, we sometimes change the order of flushes --
02382  *              but doing so can confuse the replacement policy.  This
02383  *              macro exists to allow us to specify an entry as the
02384  *              most recently touched so we can repair any such
02385  *              confusion.
02386  *
02387  *              At present, we only support the modified LRU policy, so
02388  *              this function deals with that case unconditionally.  If
02389  *              we ever support other replacement policies, the macro
02390  *              should switch on the current policy and act accordingly.
02391  *
02392  * Return:      N/A
02393  *
02394  * Programmer:  John Mainzer, 10/13/05
02395  *
02396  * Modifications:
02397  *
02398  *              JRM -- 3/20/06
02399  *              Modified macro to ignore pinned entries.  Pinned entries
02400  *              do not appear in the data structures maintained by the
02401  *              replacement policy code, and thus this macro has nothing
02402  *              to do if called for such an entry.
02403  *
02404  *              JRM -- 3/28/07
02405  *              Added sanity checks using the new is_read_only and
02406  *              ro_ref_count fields of struct H5C_cache_entry_t.
02407  *
02408  *-------------------------------------------------------------------------
02409  */
02410 
02411 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
02412 
02413 #define H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \
02414 {                                                                           \
02415     HDassert( (cache_ptr) );                                                \
02416     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                     \
02417     HDassert( (entry_ptr) );                                                \
02418     HDassert( !((entry_ptr)->is_protected) );                               \
02419     HDassert( !((entry_ptr)->is_read_only) );                               \
02420     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                           \
02421     HDassert( (entry_ptr)->size > 0 );                                      \
02422                                                                             \
02423     if ( ! ((entry_ptr)->is_pinned) ) {                                     \
02424                                                                             \
02425         /* modified LRU specific code */                                    \
02426                                                                             \
02427         /* remove the entry from the LRU list, and re-insert it at the head.\
02428          */                                                                 \
02429                                                                             \
02430         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
02431                         (cache_ptr)->LRU_tail_ptr,                          \
02432                         (cache_ptr)->LRU_list_len,                          \
02433                         (cache_ptr)->LRU_list_size, (fail_val))             \
02434                                                                             \
02435         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,            \
02436                          (cache_ptr)->LRU_tail_ptr,                         \
02437                          (cache_ptr)->LRU_list_len,                         \
02438                          (cache_ptr)->LRU_list_size, (fail_val))            \
02439                                                                             \
02440         /* Use the dirty flag to infer whether the entry is on the clean or \
02441          * dirty LRU list, and remove it.  Then insert it at the head of    \
02442          * the same LRU list.                                               \
02443          *                                                                  \
02444          * At least initially, all entries should be clean.  That may       \
02445          * change, so we may as well deal with both cases now.              \
02446          */                                                                 \
02447                                                                             \
02448         if ( (entry_ptr)->is_dirty ) {                                      \
02449             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr,    \
02450                                 (cache_ptr)->dLRU_tail_ptr,                 \
02451                                 (cache_ptr)->dLRU_list_len,                 \
02452                                 (cache_ptr)->dLRU_list_size, (fail_val))    \
02453                                                                             \
02454             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr,   \
02455                                  (cache_ptr)->dLRU_tail_ptr,                \
02456                                  (cache_ptr)->dLRU_list_len,                \
02457                                  (cache_ptr)->dLRU_list_size, (fail_val))   \
02458         } else {                                                            \
02459             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr,    \
02460                                 (cache_ptr)->cLRU_tail_ptr,                 \
02461                                 (cache_ptr)->cLRU_list_len,                 \
02462                                 (cache_ptr)->cLRU_list_size, (fail_val))    \
02463                                                                             \
02464             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,   \
02465                                  (cache_ptr)->cLRU_tail_ptr,                \
02466                                  (cache_ptr)->cLRU_list_len,                \
02467                                  (cache_ptr)->cLRU_list_size, (fail_val))   \
02468         }                                                                   \
02469                                                                             \
02470         /* End modified LRU specific code. */                               \
02471     }                                                                       \
02472 } /* H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS */
02473 
02474 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02475 
02476 #define H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS(cache_ptr, entry_ptr, fail_val) \
02477 {                                                                           \
02478     HDassert( (cache_ptr) );                                                \
02479     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                     \
02480     HDassert( (entry_ptr) );                                                \
02481     HDassert( !((entry_ptr)->is_protected) );                               \
02482     HDassert( !((entry_ptr)->is_read_only) );                               \
02483     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                           \
02484     HDassert( (entry_ptr)->size > 0 );                                      \
02485                                                                             \
02486     if ( ! ((entry_ptr)->is_pinned) ) {                                     \
02487                                                                             \
02488         /* modified LRU specific code */                                    \
02489                                                                             \
02490         /* remove the entry from the LRU list, and re-insert it at the head \
02491          */                                                                 \
02492                                                                             \
02493         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
02494                         (cache_ptr)->LRU_tail_ptr,                          \
02495                         (cache_ptr)->LRU_list_len,                          \
02496                         (cache_ptr)->LRU_list_size, (fail_val))             \
02497                                                                             \
02498         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,            \
02499                          (cache_ptr)->LRU_tail_ptr,                         \
02500                          (cache_ptr)->LRU_list_len,                         \
02501                          (cache_ptr)->LRU_list_size, (fail_val))            \
02502                                                                             \
02503         /* End modified LRU specific code. */                               \
02504     }                                                                       \
02505 } /* H5C__FAKE_RP_FOR_MOST_RECENT_ACCESS */
02506 
02507 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02508 
02509 
02510 /*-------------------------------------------------------------------------
02511  *
02512  * Macro:       H5C__UPDATE_RP_FOR_EVICTION
02513  *
02514  * Purpose:     Update the replacement policy data structures for an
02515  *              eviction of the specified cache entry.
02516  *
02517  *              At present, we only support the modified LRU policy, so
02518  *              this function deals with that case unconditionally.  If
02519  *              we ever support other replacement policies, the function
02520  *              should switch on the current policy and act accordingly.
02521  *
02522  * Return:      Non-negative on success/Negative on failure.
02523  *
02524  * Programmer:  John Mainzer, 5/10/04
02525  *
02526  * Modifications:
02527  *
02528  *              JRM - 7/27/04
02529  *              Converted the function H5C_update_rp_for_eviction() to the
02530  *              macro H5C__UPDATE_RP_FOR_EVICTION in an effort to squeeze
02531  *              a bit more performance out of the cache.
02532  *
02533  *              At least for the first cut, I am leaving the comments and
02534  *              white space in the macro.  If they cause dificulties with
02535  *              the pre-processor, I'll have to remove them.
02536  *
02537  *              JRM - 7/28/04
02538  *              Split macro into two version, one supporting the clean and
02539  *              dirty LRU lists, and the other not.  Yet another attempt
02540  *              at optimization.
02541  *
02542  *              JRM - 3/20/06
02543  *              Pinned entries can't be evicted, so this entry should never
02544  *              be called on a pinned entry.  Added assert to verify this.
02545  *
02546  *              JRM -- 3/28/07
02547  *              Added sanity checks for the new is_read_only and
02548  *              ro_ref_count fields of struct H5C_cache_entry_t.
02549  *
02550  *-------------------------------------------------------------------------
02551  */
02552 
02553 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
02554 
02555 #define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val)          \
02556 {                                                                            \
02557     HDassert( (cache_ptr) );                                                 \
02558     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                      \
02559     HDassert( (entry_ptr) );                                                 \
02560     HDassert( !((entry_ptr)->is_protected) );                                \
02561     HDassert( !((entry_ptr)->is_read_only) );                                \
02562     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                            \
02563     HDassert( !((entry_ptr)->is_pinned) );                                   \
02564     HDassert( (entry_ptr)->size > 0 );                                       \
02565                                                                              \
02566     /* modified LRU specific code */                                         \
02567                                                                              \
02568     /* remove the entry from the LRU list. */                                \
02569                                                                              \
02570     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,                  \
02571                     (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len,    \
02572                     (cache_ptr)->LRU_list_size, (fail_val))                  \
02573                                                                              \
02574     /* If the entry is clean when it is evicted, it should be on the         \
02575      * clean LRU list, if it was dirty, it should be on the dirty LRU list.  \
02576      * Remove it from the appropriate list according to the value of the     \
02577      * dirty flag.                                                           \
02578      */                                                                      \
02579                                                                              \
02580     if ( (entry_ptr)->is_dirty ) {                                           \
02581                                                                              \
02582         H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr,         \
02583                             (cache_ptr)->dLRU_tail_ptr,                      \
02584                             (cache_ptr)->dLRU_list_len,                      \
02585                             (cache_ptr)->dLRU_list_size, (fail_val))         \
02586     } else {                                                                 \
02587         H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr,         \
02588                             (cache_ptr)->cLRU_tail_ptr,                      \
02589                             (cache_ptr)->cLRU_list_len,                      \
02590                             (cache_ptr)->cLRU_list_size, (fail_val))         \
02591     }                                                                        \
02592                                                                              \
02593 } /* H5C__UPDATE_RP_FOR_EVICTION */
02594 
02595 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02596 
02597 #define H5C__UPDATE_RP_FOR_EVICTION(cache_ptr, entry_ptr, fail_val)          \
02598 {                                                                            \
02599     HDassert( (cache_ptr) );                                                 \
02600     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                      \
02601     HDassert( (entry_ptr) );                                                 \
02602     HDassert( !((entry_ptr)->is_protected) );                                \
02603     HDassert( !((entry_ptr)->is_read_only) );                                \
02604     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                            \
02605     HDassert( !((entry_ptr)->is_pinned) );                                   \
02606     HDassert( (entry_ptr)->size > 0 );                                       \
02607                                                                              \
02608     /* modified LRU specific code */                                         \
02609                                                                              \
02610     /* remove the entry from the LRU list. */                                \
02611                                                                              \
02612     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,                  \
02613                     (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len,    \
02614                     (cache_ptr)->LRU_list_size, (fail_val))                  \
02615                                                                              \
02616 } /* H5C__UPDATE_RP_FOR_EVICTION */
02617 
02618 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02619 
02620 
02621 /*-------------------------------------------------------------------------
02622  *
02623  * Macro:       H5C__UPDATE_RP_FOR_FLUSH
02624  *
02625  * Purpose:     Update the replacement policy data structures for a flush
02626  *              of the specified cache entry.
02627  *
02628  *              At present, we only support the modified LRU policy, so
02629  *              this function deals with that case unconditionally.  If
02630  *              we ever support other replacement policies, the function
02631  *              should switch on the current policy and act accordingly.
02632  *
02633  * Return:      N/A
02634  *
02635  * Programmer:  John Mainzer, 5/6/04
02636  *
02637  * Modifications:
02638  *
02639  *              JRM - 7/27/04
02640  *              Converted the function H5C_update_rp_for_flush() to the
02641  *              macro H5C__UPDATE_RP_FOR_FLUSH in an effort to squeeze
02642  *              a bit more performance out of the cache.
02643  *
02644  *              At least for the first cut, I am leaving the comments and
02645  *              white space in the macro.  If they cause dificulties with
02646  *              pre-processor, I'll have to remove them.
02647  *
02648  *              JRM - 7/28/04
02649  *              Split macro into two versions, one supporting the clean and
02650  *              dirty LRU lists, and the other not.  Yet another attempt
02651  *              at optimization.
02652  *
02653  *              JRM - 3/20/06
02654  *              While pinned entries can be flushed, they don't reside in
02655  *              the replacement policy data structures when unprotected.
02656  *              Thus I modified this macro to do nothing if the entry is
02657  *              pinned.
02658  *
02659  *              JRM - 3/28/07
02660  *              Added sanity checks based on the new is_read_only and
02661  *              ro_ref_count fields of struct H5C_cache_entry_t.
02662  *
02663  *-------------------------------------------------------------------------
02664  */
02665 
02666 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
02667 
02668 #define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val)            \
02669 {                                                                           \
02670     HDassert( (cache_ptr) );                                                \
02671     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                     \
02672     HDassert( (entry_ptr) );                                                \
02673     HDassert( !((entry_ptr)->is_protected) );                               \
02674     HDassert( !((entry_ptr)->is_read_only) );                               \
02675     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                           \
02676     HDassert( (entry_ptr)->size > 0 );                                      \
02677                                                                             \
02678     if ( ! ((entry_ptr)->is_pinned) ) {                                     \
02679                                                                             \
02680         /* modified LRU specific code */                                    \
02681                                                                             \
02682         /* remove the entry from the LRU list, and re-insert it at the      \
02683          * head.                                                            \
02684          */                                                                 \
02685                                                                             \
02686         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
02687                         (cache_ptr)->LRU_tail_ptr,                          \
02688                         (cache_ptr)->LRU_list_len,                          \
02689                         (cache_ptr)->LRU_list_size, (fail_val))             \
02690                                                                             \
02691         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,            \
02692                          (cache_ptr)->LRU_tail_ptr,                         \
02693                          (cache_ptr)->LRU_list_len,                         \
02694                          (cache_ptr)->LRU_list_size, (fail_val))            \
02695                                                                             \
02696         /* since the entry is being flushed or cleared, one would think     \
02697          * that it must be dirty -- but that need not be the case.  Use the \
02698          * dirty flag to infer whether the entry is on the clean or dirty   \
02699          * LRU list, and remove it.  Then insert it at the head of the      \
02700          * clean LRU list.                                                  \
02701          *                                                                  \
02702          * The function presumes that a dirty entry will be either cleared  \
02703          * or flushed shortly, so it is OK if we put a dirty entry on the   \
02704          * clean LRU list.                                                  \
02705          */                                                                 \
02706                                                                             \
02707         if ( (entry_ptr)->is_dirty ) {                                      \
02708             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr,    \
02709                                 (cache_ptr)->dLRU_tail_ptr,                 \
02710                                 (cache_ptr)->dLRU_list_len,                 \
02711                                 (cache_ptr)->dLRU_list_size, (fail_val))    \
02712         } else {                                                            \
02713             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr,    \
02714                                 (cache_ptr)->cLRU_tail_ptr,                 \
02715                                 (cache_ptr)->cLRU_list_len,                 \
02716                                 (cache_ptr)->cLRU_list_size, (fail_val))    \
02717         }                                                                   \
02718                                                                             \
02719         H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,       \
02720                              (cache_ptr)->cLRU_tail_ptr,                    \
02721                              (cache_ptr)->cLRU_list_len,                    \
02722                              (cache_ptr)->cLRU_list_size, (fail_val))       \
02723                                                                             \
02724         /* End modified LRU specific code. */                               \
02725     }                                                                       \
02726 } /* H5C__UPDATE_RP_FOR_FLUSH */
02727 
02728 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02729 
02730 #define H5C__UPDATE_RP_FOR_FLUSH(cache_ptr, entry_ptr, fail_val)            \
02731 {                                                                           \
02732     HDassert( (cache_ptr) );                                                \
02733     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                     \
02734     HDassert( (entry_ptr) );                                                \
02735     HDassert( !((entry_ptr)->is_protected) );                               \
02736     HDassert( !((entry_ptr)->is_read_only) );                               \
02737     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                           \
02738     HDassert( (entry_ptr)->size > 0 );                                      \
02739                                                                             \
02740     if ( ! ((entry_ptr)->is_pinned) ) {                                     \
02741                                                                             \
02742         /* modified LRU specific code */                                    \
02743                                                                             \
02744         /* remove the entry from the LRU list, and re-insert it at the      \
02745          * head.                                                            \
02746          */                                                                 \
02747                                                                             \
02748         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
02749                         (cache_ptr)->LRU_tail_ptr,                          \
02750                         (cache_ptr)->LRU_list_len,                          \
02751                         (cache_ptr)->LRU_list_size, (fail_val))             \
02752                                                                             \
02753         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,            \
02754                          (cache_ptr)->LRU_tail_ptr,                         \
02755                          (cache_ptr)->LRU_list_len,                         \
02756                          (cache_ptr)->LRU_list_size, (fail_val))            \
02757                                                                             \
02758         /* End modified LRU specific code. */                               \
02759     }                                                                       \
02760 } /* H5C__UPDATE_RP_FOR_FLUSH */
02761 
02762 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02763 
02764 
02765 /*-------------------------------------------------------------------------
02766  *
02767  * Macro:       H5C__UPDATE_RP_FOR_INSERTION
02768  *
02769  * Purpose:     Update the replacement policy data structures for an
02770  *              insertion of the specified cache entry.
02771  *
02772  *              At present, we only support the modified LRU policy, so
02773  *              this function deals with that case unconditionally.  If
02774  *              we ever support other replacement policies, the function
02775  *              should switch on the current policy and act accordingly.
02776  *
02777  * Return:      N/A
02778  *
02779  * Programmer:  John Mainzer, 5/17/04
02780  *
02781  * Modifications:
02782  *
02783  *              JRM - 7/27/04
02784  *              Converted the function H5C_update_rp_for_insertion() to the
02785  *              macro H5C__UPDATE_RP_FOR_INSERTION in an effort to squeeze
02786  *              a bit more performance out of the cache.
02787  *
02788  *              At least for the first cut, I am leaving the comments and
02789  *              white space in the macro.  If they cause dificulties with
02790  *              pre-processor, I'll have to remove them.
02791  *
02792  *              JRM - 7/28/04
02793  *              Split macro into two version, one supporting the clean and
02794  *              dirty LRU lists, and the other not.  Yet another attempt
02795  *              at optimization.
02796  *
02797  *              JRM - 3/10/06
02798  *              This macro should never be called on a pinned entry.
02799  *              Inserted an assert to verify this.
02800  *
02801  *              JRM - 8/9/06
02802  *              Not any more.  We must now allow insertion of pinned
02803  *              entries.  Updated macro to support this.
02804  *
02805  *              JRM - 3/28/07
02806  *              Added sanity checks using the new is_read_only and
02807  *              ro_ref_count fields of struct H5C_cache_entry_t.
02808  *
02809  *-------------------------------------------------------------------------
02810  */
02811 
02812 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
02813 
02814 #define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val)       \
02815 {                                                                          \
02816     HDassert( (cache_ptr) );                                               \
02817     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                    \
02818     HDassert( (entry_ptr) );                                               \
02819     HDassert( !((entry_ptr)->is_protected) );                              \
02820     HDassert( !((entry_ptr)->is_read_only) );                              \
02821     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                          \
02822     HDassert( (entry_ptr)->size > 0 );                                     \
02823                                                                            \
02824     if ( (entry_ptr)->is_pinned ) {                                        \
02825                                                                            \
02826         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr,           \
02827                          (cache_ptr)->pel_tail_ptr,                        \
02828                          (cache_ptr)->pel_len,                             \
02829                          (cache_ptr)->pel_size, (fail_val))                \
02830                                                                            \
02831     } else {                                                               \
02832                                                                            \
02833         /* modified LRU specific code */                                   \
02834                                                                            \
02835         /* insert the entry at the head of the LRU list. */                \
02836                                                                            \
02837         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
02838                          (cache_ptr)->LRU_tail_ptr,                        \
02839                          (cache_ptr)->LRU_list_len,                        \
02840                          (cache_ptr)->LRU_list_size, (fail_val))           \
02841                                                                            \
02842         /* insert the entry at the head of the clean or dirty LRU list as  \
02843          * appropriate.                                                    \
02844          */                                                                \
02845                                                                            \
02846         if ( entry_ptr->is_dirty ) {                                       \
02847             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr,  \
02848                                  (cache_ptr)->dLRU_tail_ptr,               \
02849                                  (cache_ptr)->dLRU_list_len,               \
02850                                  (cache_ptr)->dLRU_list_size, (fail_val))  \
02851         } else {                                                           \
02852             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,  \
02853                                  (cache_ptr)->cLRU_tail_ptr,               \
02854                                  (cache_ptr)->cLRU_list_len,               \
02855                                  (cache_ptr)->cLRU_list_size, (fail_val))  \
02856         }                                                                  \
02857                                                                            \
02858         /* End modified LRU specific code. */                              \
02859     }                                                                      \
02860 }
02861 
02862 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02863 
02864 #define H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, fail_val)       \
02865 {                                                                          \
02866     HDassert( (cache_ptr) );                                               \
02867     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                    \
02868     HDassert( (entry_ptr) );                                               \
02869     HDassert( !((entry_ptr)->is_protected) );                              \
02870     HDassert( !((entry_ptr)->is_read_only) );                              \
02871     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                          \
02872     HDassert( (entry_ptr)->size > 0 );                                     \
02873                                                                            \
02874     if ( (entry_ptr)->is_pinned ) {                                        \
02875                                                                            \
02876         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr,           \
02877                          (cache_ptr)->pel_tail_ptr,                        \
02878                          (cache_ptr)->pel_len,                             \
02879                          (cache_ptr)->pel_size, (fail_val))                \
02880                                                                            \
02881     } else {                                                               \
02882                                                                            \
02883         /* modified LRU specific code */                                   \
02884                                                                            \
02885         /* insert the entry at the head of the LRU list. */                \
02886                                                                            \
02887         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
02888                          (cache_ptr)->LRU_tail_ptr,                        \
02889                          (cache_ptr)->LRU_list_len,                        \
02890                          (cache_ptr)->LRU_list_size, (fail_val))           \
02891                                                                            \
02892         /* End modified LRU specific code. */                              \
02893     }                                                                      \
02894 }
02895 
02896 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
02897 
02898 
02899 /*-------------------------------------------------------------------------
02900  *
02901  * Macro:       H5C__UPDATE_RP_FOR_PROTECT
02902  *
02903  * Purpose:     Update the replacement policy data structures for a
02904  *              protect of the specified cache entry.
02905  *
02906  *              To do this, unlink the specified entry from any data
02907  *              structures used by the replacement policy, and add the
02908  *              entry to the protected list.
02909  *
02910  *              At present, we only support the modified LRU policy, so
02911  *              this function deals with that case unconditionally.  If
02912  *              we ever support other replacement policies, the function
02913  *              should switch on the current policy and act accordingly.
02914  *
02915  * Return:      N/A
02916  *
02917  * Programmer:  John Mainzer, 5/17/04
02918  *
02919  * Modifications:
02920  *
02921  *              JRM - 7/27/04
02922  *              Converted the function H5C_update_rp_for_protect() to the
02923  *              macro H5C__UPDATE_RP_FOR_PROTECT in an effort to squeeze
02924  *              a bit more performance out of the cache.
02925  *
02926  *              At least for the first cut, I am leaving the comments and
02927  *              white space in the macro.  If they cause dificulties with
02928  *              pre-processor, I'll have to remove them.
02929  *
02930  *              JRM - 7/28/04
02931  *              Split macro into two version, one supporting the clean and
02932  *              dirty LRU lists, and the other not.  Yet another attempt
02933  *              at optimization.
02934  *
02935  *              JRM - 3/17/06
02936  *              Modified macro to attempt to remove pinned entriese from
02937  *              the pinned entry list instead of from the data structures
02938  *              maintained by the replacement policy.
02939  *
02940  *              JRM - 3/28/07
02941  *              Added sanity checks based on the new is_read_only and
02942  *              ro_ref_count fields of struct H5C_cache_entry_t.
02943  *
02944  *-------------------------------------------------------------------------
02945  */
02946 
02947 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
02948 
02949 #define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val)        \
02950 {                                                                         \
02951     HDassert( (cache_ptr) );                                              \
02952     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                   \
02953     HDassert( (entry_ptr) );                                              \
02954     HDassert( !((entry_ptr)->is_protected) );                             \
02955     HDassert( !((entry_ptr)->is_read_only) );                             \
02956     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                         \
02957     HDassert( (entry_ptr)->size > 0 );                                    \
02958                                                                           \
02959     if ( (entry_ptr)->is_pinned ) {                                       \
02960                                                                           \
02961         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr,           \
02962                         (cache_ptr)->pel_tail_ptr,                        \
02963                         (cache_ptr)->pel_len,                             \
02964                         (cache_ptr)->pel_size, (fail_val))                \
02965         HDassert( (cache_ptr)->pel_len >= 0 );                            \
02966                                                                           \
02967     } else {                                                              \
02968                                                                           \
02969         /* modified LRU specific code */                                  \
02970                                                                           \
02971         /* remove the entry from the LRU list. */                         \
02972                                                                           \
02973         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
02974                         (cache_ptr)->LRU_tail_ptr,                        \
02975                         (cache_ptr)->LRU_list_len,                        \
02976                         (cache_ptr)->LRU_list_size, (fail_val))           \
02977                                                                           \
02978         /* Similarly, remove the entry from the clean or dirty LRU list   \
02979          * as appropriate.                                                \
02980          */                                                               \
02981                                                                           \
02982         if ( (entry_ptr)->is_dirty ) {                                    \
02983                                                                           \
02984             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr,  \
02985                                 (cache_ptr)->dLRU_tail_ptr,               \
02986                                 (cache_ptr)->dLRU_list_len,               \
02987                                 (cache_ptr)->dLRU_list_size, (fail_val))  \
02988                                                                           \
02989         } else {                                                          \
02990                                                                           \
02991             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr,  \
02992                                 (cache_ptr)->cLRU_tail_ptr,               \
02993                                 (cache_ptr)->cLRU_list_len,               \
02994                                 (cache_ptr)->cLRU_list_size, (fail_val))  \
02995         }                                                                 \
02996                                                                           \
02997         /* End modified LRU specific code. */                             \
02998     }                                                                     \
02999                                                                           \
03000     /* Regardless of the replacement policy, or whether the entry is      \
03001      * pinned, now add the entry to the protected list.                   \
03002      */                                                                   \
03003                                                                           \
03004     H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr,                \
03005                     (cache_ptr)->pl_tail_ptr,                             \
03006                     (cache_ptr)->pl_len,                                  \
03007                     (cache_ptr)->pl_size, (fail_val))                     \
03008 } /* H5C__UPDATE_RP_FOR_PROTECT */
03009 
03010 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03011 
03012 #define H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, fail_val)        \
03013 {                                                                         \
03014     HDassert( (cache_ptr) );                                              \
03015     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                   \
03016     HDassert( (entry_ptr) );                                              \
03017     HDassert( !((entry_ptr)->is_protected) );                             \
03018     HDassert( !((entry_ptr)->is_read_only) );                             \
03019     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                         \
03020     HDassert( (entry_ptr)->size > 0 );                                    \
03021                                                                           \
03022     if ( (entry_ptr)->is_pinned ) {                                       \
03023                                                                           \
03024         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr,           \
03025                         (cache_ptr)->pel_tail_ptr,                        \
03026                         (cache_ptr)->pel_len,                             \
03027                         (cache_ptr)->pel_size, (fail_val))                \
03028         HDassert( (cache_ptr)->pel_len >= 0 );                            \
03029                                                                           \
03030     } else {                                                              \
03031                                                                           \
03032         /* modified LRU specific code */                                  \
03033                                                                           \
03034         /* remove the entry from the LRU list. */                         \
03035                                                                           \
03036         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
03037                         (cache_ptr)->LRU_tail_ptr,                        \
03038                         (cache_ptr)->LRU_list_len,                        \
03039                         (cache_ptr)->LRU_list_size, (fail_val))           \
03040                                                                           \
03041         /* End modified LRU specific code. */                             \
03042     }                                                                     \
03043                                                                           \
03044     /* Regardless of the replacement policy, or whether the entry is      \
03045      * pinned, now add the entry to the protected list.                   \
03046      */                                                                   \
03047                                                                           \
03048     H5C__DLL_APPEND((entry_ptr), (cache_ptr)->pl_head_ptr,                \
03049                     (cache_ptr)->pl_tail_ptr,                             \
03050                     (cache_ptr)->pl_len,                                  \
03051                     (cache_ptr)->pl_size, (fail_val))                     \
03052 } /* H5C__UPDATE_RP_FOR_PROTECT */
03053 
03054 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03055 
03056 
03057 /*-------------------------------------------------------------------------
03058  *
03059  * Macro:       H5C__UPDATE_RP_FOR_RENAME
03060  *
03061  * Purpose:     Update the replacement policy data structures for a
03062  *              rename of the specified cache entry.
03063  *
03064  *              At present, we only support the modified LRU policy, so
03065  *              this function deals with that case unconditionally.  If
03066  *              we ever support other replacement policies, the function
03067  *              should switch on the current policy and act accordingly.
03068  *
03069  * Return:      N/A
03070  *
03071  * Programmer:  John Mainzer, 5/17/04
03072  *
03073  * Modifications:
03074  *
03075  *              JRM - 7/27/04
03076  *              Converted the function H5C_update_rp_for_rename() to the
03077  *              macro H5C__UPDATE_RP_FOR_RENAME in an effort to squeeze
03078  *              a bit more performance out of the cache.
03079  *
03080  *              At least for the first cut, I am leaving the comments and
03081  *              white space in the macro.  If they cause dificulties with
03082  *              pre-processor, I'll have to remove them.
03083  *
03084  *              JRM - 7/28/04
03085  *              Split macro into two version, one supporting the clean and
03086  *              dirty LRU lists, and the other not.  Yet another attempt
03087  *              at optimization.
03088  *
03089  *              JRM - 6/23/05
03090  *              Added the was_dirty parameter.  It is possible that
03091  *              the entry was clean when it was renamed -- if so it
03092  *              it is in the clean LRU regardless of the current
03093  *              value of the is_dirty field.
03094  *
03095  *              At present, all renamed entries are forced to be
03096  *              dirty.  This macro is a bit more general that that,
03097  *              to allow it to function correctly should that policy
03098  *              be relaxed in the future.
03099  *
03100  *              JRM - 3/17/06
03101  *              Modified macro to do nothing if the entry is pinned.
03102  *              In this case, the entry is on the pinned entry list, not
03103  *              in the replacement policy data structures, so there is
03104  *              nothing to be done.
03105  *
03106  *              JRM - 3/28/07
03107  *              Added sanity checks using the new is_read_only and
03108  *              ro_ref_count fields of struct H5C_cache_entry_t.
03109  *
03110  *-------------------------------------------------------------------------
03111  */
03112 
03113 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
03114 
03115 #define H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, fail_val) \
03116 {                                                                            \
03117     HDassert( (cache_ptr) );                                                 \
03118     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                      \
03119     HDassert( (entry_ptr) );                                                 \
03120     HDassert( !((entry_ptr)->is_protected) );                                \
03121     HDassert( !((entry_ptr)->is_read_only) );                                \
03122     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                            \
03123     HDassert( (entry_ptr)->size > 0 );                                       \
03124                                                                              \
03125     if ( ! ((entry_ptr)->is_pinned) ) {                                      \
03126                                                                              \
03127         /* modified LRU specific code */                                     \
03128                                                                              \
03129         /* remove the entry from the LRU list, and re-insert it at the head. \
03130          */                                                                  \
03131                                                                              \
03132         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,              \
03133                         (cache_ptr)->LRU_tail_ptr,                           \
03134                         (cache_ptr)->LRU_list_len,                           \
03135                         (cache_ptr)->LRU_list_size, (fail_val))              \
03136                                                                              \
03137         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
03138                          (cache_ptr)->LRU_tail_ptr,                          \
03139                          (cache_ptr)->LRU_list_len,                          \
03140                          (cache_ptr)->LRU_list_size, (fail_val))             \
03141                                                                              \
03142         /* remove the entry from either the clean or dirty LUR list as       \
03143          * indicated by the was_dirty parameter                              \
03144          */                                                                  \
03145         if ( was_dirty ) {                                                   \
03146                                                                              \
03147             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->dLRU_head_ptr,     \
03148                                 (cache_ptr)->dLRU_tail_ptr,                  \
03149                                 (cache_ptr)->dLRU_list_len,                  \
03150                                 (cache_ptr)->dLRU_list_size, (fail_val))     \
03151                                                                              \
03152         } else {                                                             \
03153                                                                              \
03154             H5C__AUX_DLL_REMOVE((entry_ptr), (cache_ptr)->cLRU_head_ptr,     \
03155                                 (cache_ptr)->cLRU_tail_ptr,                  \
03156                                 (cache_ptr)->cLRU_list_len,                  \
03157                                 (cache_ptr)->cLRU_list_size, (fail_val))     \
03158         }                                                                    \
03159                                                                              \
03160         /* insert the entry at the head of either the clean or dirty LRU     \
03161          * list as appropriate.                                              \
03162          */                                                                  \
03163                                                                              \
03164         if ( (entry_ptr)->is_dirty ) {                                       \
03165                                                                              \
03166             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr,    \
03167                                  (cache_ptr)->dLRU_tail_ptr,                 \
03168                                  (cache_ptr)->dLRU_list_len,                 \
03169                                  (cache_ptr)->dLRU_list_size, (fail_val))    \
03170                                                                              \
03171         } else {                                                             \
03172                                                                              \
03173             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,    \
03174                                  (cache_ptr)->cLRU_tail_ptr,                 \
03175                                  (cache_ptr)->cLRU_list_len,                 \
03176                                  (cache_ptr)->cLRU_list_size, (fail_val))    \
03177         }                                                                    \
03178                                                                              \
03179         /* End modified LRU specific code. */                                \
03180     }                                                                        \
03181 } /* H5C__UPDATE_RP_FOR_RENAME */
03182 
03183 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03184 
03185 #define H5C__UPDATE_RP_FOR_RENAME(cache_ptr, entry_ptr, was_dirty, fail_val) \
03186 {                                                                            \
03187     HDassert( (cache_ptr) );                                                 \
03188     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                      \
03189     HDassert( (entry_ptr) );                                                 \
03190     HDassert( !((entry_ptr)->is_protected) );                                \
03191     HDassert( !((entry_ptr)->is_read_only) );                                \
03192     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                            \
03193     HDassert( (entry_ptr)->size > 0 );                                       \
03194                                                                              \
03195     if ( ! ((entry_ptr)->is_pinned) ) {                                      \
03196                                                                              \
03197         /* modified LRU specific code */                                     \
03198                                                                              \
03199         /* remove the entry from the LRU list, and re-insert it at the head. \
03200          */                                                                  \
03201                                                                              \
03202         H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->LRU_head_ptr,              \
03203                         (cache_ptr)->LRU_tail_ptr,                           \
03204                         (cache_ptr)->LRU_list_len,                           \
03205                         (cache_ptr)->LRU_list_size, (fail_val))              \
03206                                                                              \
03207         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,             \
03208                          (cache_ptr)->LRU_tail_ptr,                          \
03209                          (cache_ptr)->LRU_list_len,                          \
03210                          (cache_ptr)->LRU_list_size, (fail_val))             \
03211                                                                              \
03212         /* End modified LRU specific code. */                                \
03213     }                                                                        \
03214 } /* H5C__UPDATE_RP_FOR_RENAME */
03215 
03216 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03217 
03218 
03219 /*-------------------------------------------------------------------------
03220  *
03221  * Macro:       H5C__UPDATE_RP_FOR_SIZE_CHANGE
03222  *
03223  * Purpose:     Update the replacement policy data structures for a
03224  *              size change of the specified cache entry.
03225  *
03226  *              To do this, determine if the entry is pinned.  If it is,
03227  *              update the size of the pinned entry list.
03228  *
03229  *              If it isn't pinned, the entry must handled by the
03230  *              replacement policy.  Update the appropriate replacement
03231  *              policy data structures.
03232  *
03233  *              At present, we only support the modified LRU policy, so
03234  *              this function deals with that case unconditionally.  If
03235  *              we ever support other replacement policies, the function
03236  *              should switch on the current policy and act accordingly.
03237  *
03238  * Return:      N/A
03239  *
03240  * Programmer:  John Mainzer, 8/23/06
03241  *
03242  * Modifications:
03243  *
03244  *              JRM -- 3/28/07
03245  *              Added sanity checks based on the new is_read_only and
03246  *              ro_ref_count fields of struct H5C_cache_entry_t.
03247  *
03248  *-------------------------------------------------------------------------
03249  */
03250 
03251 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
03252 
03253 #define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)    \
03254 {                                                                         \
03255     HDassert( (cache_ptr) );                                              \
03256     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                   \
03257     HDassert( (entry_ptr) );                                              \
03258     HDassert( !((entry_ptr)->is_protected) );                             \
03259     HDassert( !((entry_ptr)->is_read_only) );                             \
03260     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                         \
03261     HDassert( (entry_ptr)->size > 0 );                                    \
03262     HDassert( new_size > 0 );                                             \
03263                                                                           \
03264     if ( (entry_ptr)->is_pinned ) {                                       \
03265                                                                           \
03266         H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len,             \
03267                                         (cache_ptr)->pel_size,            \
03268                                         (entry_ptr)->size,                \
03269                                         (new_size));                      \
03270                                                                           \
03271     } else {                                                              \
03272                                                                           \
03273         /* modified LRU specific code */                                  \
03274                                                                           \
03275         /* Update the size of the LRU list */                             \
03276                                                                           \
03277         H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len,        \
03278                                         (cache_ptr)->LRU_list_size,       \
03279                                         (entry_ptr)->size,                \
03280                                         (new_size));                      \
03281                                                                           \
03282         /* Similarly, update the size of the clean or dirty LRU list as   \
03283          * appropriate.  At present, the entry must be clean, but that    \
03284          * could change.                                                  \
03285          */                                                               \
03286                                                                           \
03287         if ( (entry_ptr)->is_dirty ) {                                    \
03288                                                                           \
03289             H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->dLRU_list_len,   \
03290                                             (cache_ptr)->dLRU_list_size,  \
03291                                             (entry_ptr)->size,            \
03292                                             (new_size));                  \
03293                                                                           \
03294         } else {                                                          \
03295                                                                           \
03296             H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->cLRU_list_len,   \
03297                                             (cache_ptr)->cLRU_list_size,  \
03298                                             (entry_ptr)->size,            \
03299                                             (new_size));                  \
03300         }                                                                 \
03301                                                                           \
03302         /* End modified LRU specific code. */                             \
03303     }                                                                     \
03304                                                                           \
03305 } /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */
03306 
03307 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03308 
03309 #define H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_size)    \
03310 {                                                                         \
03311     HDassert( (cache_ptr) );                                              \
03312     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                   \
03313     HDassert( (entry_ptr) );                                              \
03314     HDassert( !((entry_ptr)->is_protected) );                             \
03315     HDassert( !((entry_ptr)->is_read_only) );                             \
03316     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                         \
03317     HDassert( (entry_ptr)->size > 0 );                                    \
03318     HDassert( new_size > 0 );                                             \
03319                                                                           \
03320     if ( (entry_ptr)->is_pinned ) {                                       \
03321                                                                           \
03322         H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->pel_len,             \
03323                                         (cache_ptr)->pel_size,            \
03324                                         (entry_ptr)->size,                \
03325                                         (new_size));                      \
03326                                                                           \
03327     } else {                                                              \
03328                                                                           \
03329         /* modified LRU specific code */                                  \
03330                                                                           \
03331         /* Update the size of the LRU list */                             \
03332                                                                           \
03333         H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr)->LRU_list_len,        \
03334                                         (cache_ptr)->LRU_list_size,       \
03335                                         (entry_ptr)->size,                \
03336                                         (new_size));                      \
03337                                                                           \
03338         /* End modified LRU specific code. */                             \
03339     }                                                                     \
03340                                                                           \
03341 } /* H5C__UPDATE_RP_FOR_SIZE_CHANGE */
03342 
03343 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03344 
03345 
03346 /*-------------------------------------------------------------------------
03347  *
03348  * Macro:       H5C__UPDATE_RP_FOR_UNPIN
03349  *
03350  * Purpose:     Update the replacement policy data structures for an
03351  *              unpin of the specified cache entry.
03352  *
03353  *              To do this, unlink the specified entry from the protected
03354  *              entry list, and re-insert it in the data structures used
03355  *              by the current replacement policy.
03356  *
03357  *              At present, we only support the modified LRU policy, so
03358  *              this function deals with that case unconditionally.  If
03359  *              we ever support other replacement policies, the macro
03360  *              should switch on the current policy and act accordingly.
03361  *
03362  * Return:      N/A
03363  *
03364  * Programmer:  John Mainzer, 3/22/06
03365  *
03366  * Modifications:
03367  *
03368  *              JRM -- 3/28/07
03369  *              Added sanity checks based on the new is_read_only and
03370  *              ro_ref_count fields of struct H5C_cache_entry_t.
03371  *
03372  *-------------------------------------------------------------------------
03373  */
03374 
03375 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
03376 
03377 #define H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val)       \
03378 {                                                                      \
03379     HDassert( (cache_ptr) );                                           \
03380     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                \
03381     HDassert( (entry_ptr) );                                           \
03382     HDassert( !((entry_ptr)->is_protected) );                          \
03383     HDassert( !((entry_ptr)->is_read_only) );                          \
03384     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                      \
03385     HDassert( (entry_ptr)->is_pinned);                                 \
03386     HDassert( (entry_ptr)->size > 0 );                                 \
03387                                                                        \
03388     /* Regardless of the replacement policy, remove the entry from the \
03389      * pinned entry list.                                              \
03390      */                                                                \
03391     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr,            \
03392                     (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len,   \
03393                     (cache_ptr)->pel_size, (fail_val))                 \
03394     HDassert( (cache_ptr)->pel_len >= 0 );                             \
03395                                                                        \
03396     /* modified LRU specific code */                                   \
03397                                                                        \
03398     /* insert the entry at the head of the LRU list. */                \
03399                                                                        \
03400     H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
03401                      (cache_ptr)->LRU_tail_ptr,                        \
03402                      (cache_ptr)->LRU_list_len,                        \
03403                      (cache_ptr)->LRU_list_size, (fail_val))           \
03404                                                                        \
03405     /* Similarly, insert the entry at the head of either the clean or  \
03406      * dirty LRU list as appropriate.                                  \
03407      */                                                                \
03408                                                                        \
03409     if ( (entry_ptr)->is_dirty ) {                                     \
03410                                                                        \
03411         H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr,  \
03412                              (cache_ptr)->dLRU_tail_ptr,               \
03413                              (cache_ptr)->dLRU_list_len,               \
03414                              (cache_ptr)->dLRU_list_size, (fail_val))  \
03415                                                                        \
03416     } else {                                                           \
03417                                                                        \
03418         H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,  \
03419                              (cache_ptr)->cLRU_tail_ptr,               \
03420                              (cache_ptr)->cLRU_list_len,               \
03421                              (cache_ptr)->cLRU_list_size, (fail_val))  \
03422     }                                                                  \
03423                                                                        \
03424     /* End modified LRU specific code. */                              \
03425                                                                        \
03426 } /* H5C__UPDATE_RP_FOR_UNPIN */
03427 
03428 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03429 
03430 #define H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, fail_val)       \
03431 {                                                                      \
03432     HDassert( (cache_ptr) );                                           \
03433     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                \
03434     HDassert( (entry_ptr) );                                           \
03435     HDassert( !((entry_ptr)->is_protected) );                          \
03436     HDassert( !((entry_ptr)->is_read_only) );                          \
03437     HDassert( ((entry_ptr)->ro_ref_count) == 0 );                      \
03438     HDassert( (entry_ptr)->is_pinned);                                 \
03439     HDassert( (entry_ptr)->size > 0 );                                 \
03440                                                                        \
03441     /* Regardless of the replacement policy, remove the entry from the \
03442      * pinned entry list.                                              \
03443      */                                                                \
03444     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pel_head_ptr,            \
03445                     (cache_ptr)->pel_tail_ptr, (cache_ptr)->pel_len,   \
03446                     (cache_ptr)->pel_size, (fail_val))                 \
03447     HDassert( (cache_ptr)->pel_len >= 0 );                             \
03448                                                                        \
03449     /* modified LRU specific code */                                   \
03450                                                                        \
03451     /* insert the entry at the head of the LRU list. */                \
03452                                                                        \
03453     H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
03454                      (cache_ptr)->LRU_tail_ptr,                        \
03455                      (cache_ptr)->LRU_list_len,                        \
03456                      (cache_ptr)->LRU_list_size, (fail_val))           \
03457                                                                        \
03458     /* End modified LRU specific code. */                              \
03459                                                                        \
03460 } /* H5C__UPDATE_RP_FOR_UNPIN */
03461 
03462 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03463 
03464 
03465 /*-------------------------------------------------------------------------
03466  *
03467  * Macro:       H5C__UPDATE_RP_FOR_UNPROTECT
03468  *
03469  * Purpose:     Update the replacement policy data structures for an
03470  *              unprotect of the specified cache entry.
03471  *
03472  *              To do this, unlink the specified entry from the protected
03473  *              list, and re-insert it in the data structures used by the
03474  *              current replacement policy.
03475  *
03476  *              At present, we only support the modified LRU policy, so
03477  *              this function deals with that case unconditionally.  If
03478  *              we ever support other replacement policies, the function
03479  *              should switch on the current policy and act accordingly.
03480  *
03481  * Return:      N/A
03482  *
03483  * Programmer:  John Mainzer, 5/19/04
03484  *
03485  * Modifications:
03486  *
03487  *              JRM - 7/27/04
03488  *              Converted the function H5C_update_rp_for_unprotect() to
03489  *              the macro H5C__UPDATE_RP_FOR_UNPROTECT in an effort to
03490  *              squeeze a bit more performance out of the cache.
03491  *
03492  *              At least for the first cut, I am leaving the comments and
03493  *              white space in the macro.  If they cause dificulties with
03494  *              pre-processor, I'll have to remove them.
03495  *
03496  *              JRM - 7/28/04
03497  *              Split macro into two version, one supporting the clean and
03498  *              dirty LRU lists, and the other not.  Yet another attempt
03499  *              at optimization.
03500  *
03501  *              JRM - 3/17/06
03502  *              Modified macro to put pinned entries on the pinned entry
03503  *              list instead of inserting them in the data structures
03504  *              maintained by the replacement policy.
03505  *
03506  *-------------------------------------------------------------------------
03507  */
03508 
03509 #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS
03510 
03511 #define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val)       \
03512 {                                                                          \
03513     HDassert( (cache_ptr) );                                               \
03514     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                    \
03515     HDassert( (entry_ptr) );                                               \
03516     HDassert( (entry_ptr)->is_protected);                                  \
03517     HDassert( (entry_ptr)->size > 0 );                                     \
03518                                                                            \
03519     /* Regardless of the replacement policy, remove the entry from the     \
03520      * protected list.                                                     \
03521      */                                                                    \
03522     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr,                 \
03523                     (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len,         \
03524                     (cache_ptr)->pl_size, (fail_val))                      \
03525                                                                            \
03526     if ( (entry_ptr)->is_pinned ) {                                        \
03527                                                                            \
03528         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr,           \
03529                          (cache_ptr)->pel_tail_ptr,                        \
03530                          (cache_ptr)->pel_len,                             \
03531                          (cache_ptr)->pel_size, (fail_val))                \
03532                                                                            \
03533     } else {                                                               \
03534                                                                            \
03535         /* modified LRU specific code */                                   \
03536                                                                            \
03537         /* insert the entry at the head of the LRU list. */                \
03538                                                                            \
03539         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
03540                          (cache_ptr)->LRU_tail_ptr,                        \
03541                          (cache_ptr)->LRU_list_len,                        \
03542                          (cache_ptr)->LRU_list_size, (fail_val))           \
03543                                                                            \
03544         /* Similarly, insert the entry at the head of either the clean or  \
03545          * dirty LRU list as appropriate.                                  \
03546          */                                                                \
03547                                                                            \
03548         if ( (entry_ptr)->is_dirty ) {                                     \
03549                                                                            \
03550             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->dLRU_head_ptr,  \
03551                                  (cache_ptr)->dLRU_tail_ptr,               \
03552                                  (cache_ptr)->dLRU_list_len,               \
03553                                  (cache_ptr)->dLRU_list_size, (fail_val))  \
03554                                                                            \
03555         } else {                                                           \
03556                                                                            \
03557             H5C__AUX_DLL_PREPEND((entry_ptr), (cache_ptr)->cLRU_head_ptr,  \
03558                                  (cache_ptr)->cLRU_tail_ptr,               \
03559                                  (cache_ptr)->cLRU_list_len,               \
03560                                  (cache_ptr)->cLRU_list_size, (fail_val))  \
03561         }                                                                  \
03562                                                                            \
03563         /* End modified LRU specific code. */                              \
03564     }                                                                      \
03565                                                                            \
03566 } /* H5C__UPDATE_RP_FOR_UNPROTECT */
03567 
03568 #else /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03569 
03570 #define H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, fail_val)       \
03571 {                                                                          \
03572     HDassert( (cache_ptr) );                                               \
03573     HDassert( (cache_ptr)->magic == H5C__H5C_T_MAGIC );                    \
03574     HDassert( (entry_ptr) );                                               \
03575     HDassert( (entry_ptr)->is_protected);                                  \
03576     HDassert( (entry_ptr)->size > 0 );                                     \
03577                                                                            \
03578     /* Regardless of the replacement policy, remove the entry from the     \
03579      * protected list.                                                     \
03580      */                                                                    \
03581     H5C__DLL_REMOVE((entry_ptr), (cache_ptr)->pl_head_ptr,                 \
03582                     (cache_ptr)->pl_tail_ptr, (cache_ptr)->pl_len,         \
03583                     (cache_ptr)->pl_size, (fail_val))                      \
03584                                                                            \
03585     if ( (entry_ptr)->is_pinned ) {                                        \
03586                                                                            \
03587         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->pel_head_ptr,           \
03588                          (cache_ptr)->pel_tail_ptr,                        \
03589                          (cache_ptr)->pel_len,                             \
03590                          (cache_ptr)->pel_size, (fail_val))                \
03591                                                                            \
03592     } else {                                                               \
03593                                                                            \
03594         /* modified LRU specific code */                                   \
03595                                                                            \
03596         /* insert the entry at the head of the LRU list. */                \
03597                                                                            \
03598         H5C__DLL_PREPEND((entry_ptr), (cache_ptr)->LRU_head_ptr,           \
03599                          (cache_ptr)->LRU_tail_ptr,                        \
03600                          (cache_ptr)->LRU_list_len,                        \
03601                          (cache_ptr)->LRU_list_size, (fail_val))           \
03602                                                                            \
03603         /* End modified LRU specific code. */                              \
03604     }                                                                      \
03605 } /* H5C__UPDATE_RP_FOR_UNPROTECT */
03606 
03607 #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */
03608 
03609 
03610 #endif /* _H5Cpkg_H */
03611