home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / client / sysint / acache.c next >
C/C++ Source or Header  |  2009-09-03  |  28KB  |  933 lines

  1. /*
  2.  * Copyright ⌐ Acxiom Corporation, 2005
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.   
  7. #include <assert.h>
  8. #include <string.h>
  9.   
  10. #include "pvfs2-attr.h"
  11. #include "acache.h"
  12. #include "tcache.h"
  13. #include "pint-util.h"
  14. #include "pvfs2-debug.h"
  15. #include "gossip.h"
  16. #include "pvfs2-internal.h"
  17.   
  18. /** \file
  19.  *  \ingroup acache
  20.  * Implementation of the Attribute Cache (acache) component.
  21.  */
  22.   
  23. /* compile time defaults */
  24. #define ACACHE_DEFAULT_TIMEOUT_MSECS 5000
  25. #define ACACHE_DEFAULT_SOFT_LIMIT 5120
  26. #define ACACHE_DEFAULT_HARD_LIMIT 10240
  27. #define ACACHE_DEFAULT_RECLAIM_PERCENTAGE 25
  28. #define ACACHE_DEFAULT_REPLACE_ALGORITHM LEAST_RECENTLY_USED
  29.  
  30. /* this one is modeled after TROVE_DEFAULT_HANDLE_PURGATORY_SEC */
  31. #define STATIC_ACACHE_DEFAULT_TIMEOUT_MSECS 360000
  32.  
  33. struct PINT_perf_key acache_keys[] = 
  34. {
  35.    {"ACACHE_NUM_ENTRIES", PERF_ACACHE_NUM_ENTRIES, PINT_PERF_PRESERVE},
  36.    {"ACACHE_SOFT_LIMIT", PERF_ACACHE_SOFT_LIMIT, PINT_PERF_PRESERVE},
  37.    {"ACACHE_HARD_LIMIT", PERF_ACACHE_HARD_LIMIT, PINT_PERF_PRESERVE},
  38.    {"ACACHE_HITS", PERF_ACACHE_HITS, 0},
  39.    {"ACACHE_MISSES", PERF_ACACHE_MISSES, 0},
  40.    {"ACACHE_UPDATES", PERF_ACACHE_UPDATES, 0},
  41.    {"ACACHE_PURGES", PERF_ACACHE_PURGES, 0},
  42.    {"ACACHE_REPLACEMENTS", PERF_ACACHE_REPLACEMENTS, 0},
  43.    {"ACACHE_DELETIONS", PERF_ACACHE_DELETIONS, 0},
  44.    {"ACACHE_ENABLED", PERF_ACACHE_ENABLED, PINT_PERF_PRESERVE},
  45.    {NULL, 0, 0},
  46. };
  47.  
  48. /* non-static data to be stored in a cached entry */
  49. struct acache_payload
  50. {
  51.     PVFS_object_ref refn;    /* PVFS2 object reference */
  52.     PVFS_object_attr attr;   /* cached attributes */  
  53.     int attr_status;         /* are the attributes valid? */
  54.     PVFS_size size;          /* cached size */
  55.     int size_status;         /* is the size valid? */
  56. };
  57.  
  58. /* static data to be stored in a cached entry */
  59. struct static_payload
  60. {
  61.     PVFS_object_ref refn;    /* PVFS2 object reference */
  62.     uint32_t mask;
  63.  
  64.     /* static fields that can be cached separately */
  65.     PVFS_ds_type objtype;
  66.     PINT_dist *dist;
  67.     uint32_t dist_size;
  68.     PVFS_handle *dfile_array;
  69.     uint32_t dfile_count;
  70.     PVFS_handle *mirror_dfile_array;
  71.     uint32_t mirror_copies_count;
  72. };
  73.   
  74. static struct PINT_tcache* acache = NULL;
  75. static struct PINT_tcache* static_acache = NULL;
  76. static gen_mutex_t acache_mutex = GEN_MUTEX_INITIALIZER;
  77.   
  78. static int acache_compare_key_entry(void* key, struct qhash_head* link);
  79. static int acache_free_payload(void* payload);
  80. static int static_compare_key_entry(void* key, struct qhash_head* link);
  81. static int static_free_payload(void* payload);
  82.  
  83. static int acache_hash_key(void* key, int table_size);
  84. static struct PINT_perf_counter* acache_pc = NULL;
  85. static struct PINT_perf_counter* static_pc = NULL;
  86. static int set_tcache_defaults(struct PINT_tcache* instance);
  87.  
  88. static void load_payload(struct PINT_tcache* instance, 
  89.     PVFS_object_ref refn,
  90.     void* payload,
  91.     struct PINT_perf_counter* pc);
  92.  
  93. /**
  94.  * Enables perf counter instrumentation of the acache
  95.  */
  96. void PINT_acache_enable_perf_counter(
  97.     struct PINT_perf_counter* pc_in, /**< counter for non static fields */
  98.     struct PINT_perf_counter* static_pc_in) /**< counter for static fields */
  99. {
  100.     gen_mutex_lock(&acache_mutex);
  101.  
  102.     acache_pc = pc_in;
  103.     assert(acache_pc);
  104.  
  105.     static_pc = static_pc_in;
  106.     assert(static_pc);
  107.  
  108.     /* set initial values */
  109.     PINT_perf_count(acache_pc, PERF_ACACHE_SOFT_LIMIT,
  110.         acache->soft_limit, PINT_PERF_SET);
  111.     PINT_perf_count(acache_pc, PERF_ACACHE_HARD_LIMIT,
  112.         acache->hard_limit, PINT_PERF_SET);
  113.     PINT_perf_count(acache_pc, PERF_ACACHE_ENABLED,
  114.         acache->enable, PINT_PERF_SET);
  115.  
  116.     PINT_perf_count(static_pc, PERF_ACACHE_SOFT_LIMIT,
  117.         static_acache->soft_limit, PINT_PERF_SET);
  118.     PINT_perf_count(static_pc, PERF_ACACHE_HARD_LIMIT,
  119.         static_acache->hard_limit, PINT_PERF_SET);
  120.     PINT_perf_count(static_pc, PERF_ACACHE_ENABLED,
  121.         static_acache->enable, PINT_PERF_SET);
  122.  
  123.     gen_mutex_unlock(&acache_mutex);
  124.  
  125.     return;
  126. }
  127.  
  128. /**
  129.  * Initializes the acache 
  130.  * \return pointer to tcache on success, NULL on failure
  131.  */
  132. int PINT_acache_initialize(void)
  133. {
  134.     int ret = -1;
  135.   
  136.     gen_mutex_lock(&acache_mutex);
  137.   
  138.     /* create tcache instances */
  139.     acache = PINT_tcache_initialize(acache_compare_key_entry,
  140.                                     acache_hash_key,
  141.                                     acache_free_payload,
  142.                                     -1 /* default tcache table size */);
  143.     if(!acache)
  144.     {
  145.         gen_mutex_unlock(&acache_mutex);
  146.         return(-PVFS_ENOMEM);
  147.     }
  148.  
  149.     static_acache = PINT_tcache_initialize(static_compare_key_entry,
  150.                                     acache_hash_key,
  151.                                     static_free_payload,
  152.                                     -1 /* default tcache table size */);
  153.     if(!static_acache)
  154.     {
  155.         PINT_tcache_finalize(acache);
  156.         gen_mutex_unlock(&acache_mutex);
  157.         return(-PVFS_ENOMEM);
  158.     }
  159.   
  160.     /* fill in defaults that are specific to non-static cache */
  161.     ret = PINT_tcache_set_info(acache, TCACHE_TIMEOUT_MSECS,
  162.                                ACACHE_DEFAULT_TIMEOUT_MSECS);
  163.     if(ret < 0)
  164.     {
  165.         PINT_tcache_finalize(acache);
  166.         PINT_tcache_finalize(static_acache);
  167.         gen_mutex_unlock(&acache_mutex);
  168.         return(ret);
  169.     }
  170.  
  171.     /* fill in defaults that are specific to static cache */
  172.     ret = PINT_tcache_set_info(static_acache, TCACHE_TIMEOUT_MSECS,
  173.                                STATIC_ACACHE_DEFAULT_TIMEOUT_MSECS);
  174.     if(ret < 0)
  175.     {
  176.         PINT_tcache_finalize(acache);
  177.         PINT_tcache_finalize(static_acache);
  178.         gen_mutex_unlock(&acache_mutex);
  179.         return(ret);
  180.     }
  181.  
  182.     /* fill in defaults that are common to both */
  183.     ret = set_tcache_defaults(acache);
  184.     if(ret < 0)
  185.     {
  186.         PINT_tcache_finalize(acache);
  187.         PINT_tcache_finalize(static_acache);
  188.         gen_mutex_unlock(&acache_mutex);
  189.         return(ret);
  190.     }
  191.  
  192.     ret = set_tcache_defaults(static_acache);
  193.     if(ret < 0)
  194.     {
  195.         PINT_tcache_finalize(acache);
  196.         PINT_tcache_finalize(static_acache);
  197.         gen_mutex_unlock(&acache_mutex);
  198.         return(ret);
  199.     }
  200.   
  201.     gen_mutex_unlock(&acache_mutex);
  202.     return(0);
  203. }
  204.   
  205. /** Finalizes and destroys the acache, frees all cached entries */
  206. void PINT_acache_finalize(void)
  207. {
  208.     gen_mutex_lock(&acache_mutex);
  209.  
  210.     PINT_tcache_finalize(acache);
  211.     PINT_tcache_finalize(static_acache);
  212.     acache = NULL;
  213.     static_acache = NULL;
  214.  
  215.     gen_mutex_unlock(&acache_mutex);
  216.     return;
  217. }
  218.   
  219. /**
  220.  * Retrieves parameters from the acache 
  221.  * @see PINT_tcache_options
  222.  * \return 0 on success, -PVFS_error on failure
  223.  */
  224. int PINT_acache_get_info(
  225.     enum PINT_acache_options option, /**< option to read */
  226.     unsigned int* arg)                   /**< output value */
  227. {
  228.     int ret = -1;
  229.     
  230.     gen_mutex_lock(&acache_mutex);
  231.  
  232.     if(option & STATIC_ACACHE_OPT)
  233.     {
  234.         /* this is a static acache option; strip mask and pass along to
  235.          * tcache
  236.          */
  237.         option -= STATIC_ACACHE_OPT;
  238.         ret = PINT_tcache_get_info(static_acache, option, arg);
  239.     }
  240.     else
  241.     {
  242.         ret = PINT_tcache_get_info(acache, option, arg);
  243.     }
  244.   
  245.     gen_mutex_unlock(&acache_mutex);
  246.   
  247.     return(ret);
  248. }
  249.   
  250. /**
  251.  * Sets optional parameters in the acache
  252.  * @see PINT_tcache_options
  253.  * @return 0 on success, -PVFS_error on failure
  254.  */
  255. int PINT_acache_set_info(
  256.     enum PINT_acache_options option, /**< option to modify */
  257.     unsigned int arg)             /**< input value */
  258. {
  259.     int ret = -1;
  260.   
  261.     gen_mutex_lock(&acache_mutex);
  262.  
  263.     if(option & STATIC_ACACHE_OPT)
  264.     {
  265.         /* this is a static acache option; strip mask and pass along to
  266.          * tcache
  267.          */
  268.         option -= STATIC_ACACHE_OPT;
  269.         ret = PINT_tcache_set_info(static_acache, option, arg);
  270.  
  271.         /* record any parameter changes that may have resulted*/
  272.         PINT_perf_count(static_pc, PERF_ACACHE_SOFT_LIMIT,
  273.             static_acache->soft_limit, PINT_PERF_SET);
  274.         PINT_perf_count(static_pc, PERF_ACACHE_HARD_LIMIT,
  275.             static_acache->hard_limit, PINT_PERF_SET);
  276.         PINT_perf_count(static_pc, PERF_ACACHE_ENABLED,
  277.             static_acache->enable, PINT_PERF_SET);
  278.         PINT_perf_count(static_pc, PERF_ACACHE_NUM_ENTRIES,
  279.             static_acache->num_entries, PINT_PERF_SET);
  280.     }
  281.     else
  282.     {
  283.         ret = PINT_tcache_set_info(acache, option, arg);
  284.  
  285.         /* record any parameter changes that may have resulted*/
  286.         PINT_perf_count(acache_pc, PERF_ACACHE_SOFT_LIMIT,
  287.             acache->soft_limit, PINT_PERF_SET);
  288.         PINT_perf_count(acache_pc, PERF_ACACHE_HARD_LIMIT,
  289.             acache->hard_limit, PINT_PERF_SET);
  290.         PINT_perf_count(acache_pc, PERF_ACACHE_ENABLED,
  291.             acache->enable, PINT_PERF_SET);
  292.         PINT_perf_count(acache_pc, PERF_ACACHE_NUM_ENTRIES,
  293.             acache->num_entries, PINT_PERF_SET);
  294.     }
  295.  
  296.     gen_mutex_unlock(&acache_mutex);
  297.  
  298.     return(ret);
  299. }
  300.   
  301. /** 
  302.  * Retrieves a _copy_ of a cached attributes structure.  Also retrieves the
  303.  * logical file size (if the object in question is a file) and reports the
  304.  * status of both the attributes and size to indicate if they are valid or
  305.  * not
  306.  * @return 0 on success, -PVFS_error on failure
  307.  */
  308. int PINT_acache_get_cached_entry(
  309.     PVFS_object_ref refn,  /**< PVFS2 object to look up */
  310.     PVFS_object_attr* attr,/**< attributes of the object */
  311.     int* attr_status,      /**< indicates if the attributes are expired or not */
  312.     PVFS_size* size,       /**< logical size of the object (only valid for files) */
  313.     int* size_status)      /**< indicates if the size has expired or not */
  314. {
  315.     int ret = -1;
  316.     struct PINT_tcache_entry* tmp_entry;
  317.     struct acache_payload* tmp_payload;
  318.     struct static_payload* tmp_static_payload;
  319.     int status;
  320.   
  321.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: get_cached_entry(): H=%llu\n",
  322.                  llu(refn.handle));
  323.   
  324.     /* assume everything is timed out for starters */
  325.     *attr_status = -PVFS_ETIME;
  326.     *size_status = -PVFS_ETIME;
  327.     attr->mask = 0;
  328.   
  329.     gen_mutex_lock(&acache_mutex);
  330.   
  331.     /* lookup static components */
  332.     ret = PINT_tcache_lookup(static_acache, &refn, &tmp_entry, &status);
  333.     if(ret < 0 || status != 0)
  334.     {
  335.         PINT_perf_count(static_pc, PERF_ACACHE_MISSES, 1, PINT_PERF_ADD);
  336.         gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: miss static: H=%llu\n",
  337.                      llu(refn.handle));
  338.         tmp_static_payload = NULL;
  339.     }
  340.     else
  341.     {
  342.         PINT_perf_count(static_pc, PERF_ACACHE_HITS, 1, PINT_PERF_ADD);
  343.         tmp_static_payload = tmp_entry->payload;
  344.     }
  345.   
  346.     /* lookup non-static components */
  347.     ret = PINT_tcache_lookup(acache, &refn, &tmp_entry, &status);
  348.     if(ret < 0 || status != 0)
  349.     {
  350.         PINT_perf_count(acache_pc, PERF_ACACHE_MISSES, 1, PINT_PERF_ADD);
  351.         gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: miss non-static: H=%llu\n",
  352.                      llu(refn.handle));
  353.         tmp_payload = NULL;
  354.     }
  355.     else
  356.     {
  357.         PINT_perf_count(acache_pc, PERF_ACACHE_HITS, 1, PINT_PERF_ADD);
  358.         tmp_payload = tmp_entry->payload;
  359.     }
  360.  
  361.     if(!tmp_payload && !tmp_static_payload)
  362.     {
  363.         /* missed everything */
  364.         gen_mutex_unlock(&acache_mutex);
  365.         return(ret);
  366.     }
  367.  
  368. #if 0
  369.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: 
  370. status=%d, attr_status=%d, size_status=%d\n",
  371.                  status, tmp_payload->attr_status, tmp_payload->size_status);
  372. #endif
  373.  
  374.     /* copy out non-static attributes if valid */
  375.     if(tmp_payload && tmp_payload->attr_status == 0)
  376.     {
  377.         gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: copying out attr.\n");
  378.         ret = PINT_copy_object_attr(attr, &(tmp_payload->attr));
  379.         if(ret < 0)
  380.         {
  381.             gen_mutex_unlock(&acache_mutex);
  382.             return(ret);
  383.         }
  384.         *attr_status = 0;
  385.     }
  386.   
  387.     /* copy out size if valid */
  388.     if(tmp_payload && tmp_payload->size_status == 0)
  389.     {
  390.         gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: copying out size.\n");
  391.         *size = tmp_payload->size;
  392.         *size_status = 0;
  393.     }
  394.   
  395.     /* copy out static attributes if valid */
  396.     if(tmp_static_payload)
  397.     {
  398.         attr->mask |= tmp_static_payload->mask;
  399.         if(tmp_static_payload->mask & PVFS_ATTR_COMMON_TYPE)
  400.         {
  401.             attr->objtype = tmp_static_payload->objtype;
  402.         }
  403.         if(tmp_static_payload->mask & PVFS_ATTR_META_DFILES)
  404.         {
  405.             if(attr->u.meta.dfile_array)
  406.                 free(attr->u.meta.dfile_array);
  407.             attr->u.meta.dfile_array = 
  408.                 malloc(tmp_static_payload->dfile_count*sizeof(PVFS_handle));
  409.             if(!attr->u.meta.dfile_array)
  410.             {
  411.                 gen_mutex_unlock(&acache_mutex);
  412.                 return(-PVFS_ENOMEM);
  413.             }
  414.             memcpy(attr->u.meta.dfile_array, tmp_static_payload->dfile_array,
  415.                 tmp_static_payload->dfile_count*sizeof(PVFS_handle));
  416.             attr->u.meta.dfile_count = tmp_static_payload->dfile_count;
  417.         }
  418.         if(tmp_static_payload->mask & PVFS_ATTR_META_MIRROR_DFILES)
  419.         {
  420.             if(attr->u.meta.mirror_dfile_array)
  421.                 free(attr->u.meta.mirror_dfile_array);
  422.             attr->u.meta.mirror_dfile_array = 
  423.                 malloc(tmp_static_payload->dfile_count*sizeof(PVFS_handle)*
  424.                        tmp_static_payload->mirror_copies_count);
  425.             if(!attr->u.meta.mirror_dfile_array)
  426.             {
  427.                 gen_mutex_unlock(&acache_mutex);
  428.                 return(-PVFS_ENOMEM);
  429.             }
  430.             memcpy(attr->u.meta.mirror_dfile_array
  431.                   ,tmp_static_payload->mirror_dfile_array
  432.                   ,tmp_static_payload->dfile_count*sizeof(PVFS_handle)*
  433.                    tmp_static_payload->mirror_copies_count);
  434.             attr->u.meta.mirror_copies_count = 
  435.                      tmp_static_payload->mirror_copies_count;
  436.         }
  437.         if(tmp_static_payload->mask & PVFS_ATTR_META_DIST)
  438.         {
  439.             if(attr->u.meta.dist)
  440.                 PINT_dist_free(attr->u.meta.dist);
  441.             attr->u.meta.dist = PINT_dist_copy(tmp_static_payload->dist);
  442.             if(!attr->u.meta.dist)
  443.             {
  444.                 if(attr->u.meta.dfile_array)
  445.                     free(attr->u.meta.dfile_array);
  446.                 gen_mutex_unlock(&acache_mutex);
  447.                 return(-PVFS_ENOMEM);
  448.             }
  449.             attr->u.meta.dist_size = tmp_static_payload->dist_size;
  450.         }
  451.         *attr_status = 0;
  452.     }
  453.  
  454.     gen_mutex_unlock(&acache_mutex);
  455.   
  456.     gossip_debug(GOSSIP_ACACHE_DEBUG, 
  457.                  "acache: hit: H=%llu, "
  458.                  "size_status=%d, attr_status=%d\n",
  459.                  llu(refn.handle), *size_status, *attr_status);
  460.   
  461.     if(*size_status == 0 || *attr_status == 0)
  462.     {
  463.         /* return success if we got _anything_ out of the cache */
  464.         return(0);
  465.     }
  466.   
  467.     return(-PVFS_ETIME);
  468. }
  469.   
  470. /**
  471.  * Invalidates a cache entry (if present)
  472.  */
  473. void PINT_acache_invalidate(
  474.     PVFS_object_ref refn)
  475. {
  476.     int ret = -1;
  477.     struct PINT_tcache_entry* tmp_entry;
  478.     int tmp_status;
  479.   
  480.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: invalidate(): H=%llu\n",
  481.                  llu(refn.handle));
  482.   
  483.     gen_mutex_lock(&acache_mutex);
  484.   
  485.     /* find out if we have non-static items cached */
  486.     ret = PINT_tcache_lookup(acache, 
  487.                              &refn,
  488.                              &tmp_entry,
  489.                              &tmp_status);
  490.     if(ret == 0)
  491.     {
  492.         PINT_tcache_delete(acache, tmp_entry);
  493.         PINT_perf_count(acache_pc, PERF_ACACHE_DELETIONS, 1,
  494.                         PINT_PERF_ADD);
  495.     }
  496.   
  497.     /* find out if we have static items cached */
  498.     ret = PINT_tcache_lookup(static_acache, 
  499.                              &refn,
  500.                              &tmp_entry,
  501.                              &tmp_status);
  502.     if(ret == 0)
  503.     {
  504.         PINT_tcache_delete(static_acache, tmp_entry);
  505.         PINT_perf_count(static_pc, PERF_ACACHE_DELETIONS, 1,
  506.                         PINT_PERF_ADD);
  507.     }
  508.  
  509.     /* set the new current number of entries */
  510.     PINT_perf_count(acache_pc, PERF_ACACHE_NUM_ENTRIES,
  511.                     acache->num_entries, PINT_PERF_SET);
  512.     PINT_perf_count(static_pc, PERF_ACACHE_NUM_ENTRIES,
  513.                     static_acache->num_entries, PINT_PERF_SET);
  514.  
  515.     gen_mutex_unlock(&acache_mutex);
  516.     return;
  517. }
  518.   
  519.   
  520. /**
  521.  * Invalidates only the logical size assocated with an entry (if present)
  522.  */
  523. void PINT_acache_invalidate_size(
  524.     PVFS_object_ref refn)
  525. {
  526.     int ret = -1;
  527.     struct PINT_tcache_entry* tmp_entry;
  528.     struct acache_payload* tmp_payload;
  529.     int tmp_status;
  530.   
  531.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: invalidate_size(): H=%llu\n",
  532.                  llu(refn.handle));
  533.   
  534.     gen_mutex_lock(&acache_mutex);
  535.  
  536.     /* find out if the entry is in the cache */
  537.     ret = PINT_tcache_lookup(acache, 
  538.                              &refn,
  539.                              &tmp_entry,
  540.                              &tmp_status);
  541.     if(ret == 0)
  542.     {
  543.         /* found match in cache; set size to invalid */
  544.         tmp_payload = tmp_entry->payload;
  545.         tmp_payload->size_status = -PVFS_ETIME;
  546.     }
  547.   
  548.     PINT_perf_count(acache_pc, PERF_ACACHE_NUM_ENTRIES,
  549.                     acache->num_entries, PINT_PERF_SET);
  550.  
  551.     gen_mutex_unlock(&acache_mutex);
  552.     return;
  553. }
  554.   
  555. /** 
  556.  * Adds a set of attributes to the cache, or updates them if they are already
  557.  * present.  The given attributes are _copied_ into the cache.   Size
  558.  * parameter will not be updated if it is NULL.
  559.  *
  560.  * \note NOTE: All previous attribute and size information for the object
  561.  * will be discarded, even if there is still time remaining before it expires
  562.  * and the new attributes and/or size contain less information.
  563.  *
  564.  * \return 0 on success, -PVFS_error on failure
  565.  */
  566. int PINT_acache_update(
  567.     PVFS_object_ref refn,   /**< object to update */
  568.     PVFS_object_attr *attr, /**< attributes to copy into cache */
  569.     PVFS_size* size)        /**< logical file size (NULL if not available) */
  570. {
  571.     struct acache_payload* tmp_payload = NULL;
  572.     struct static_payload* tmp_static_payload = NULL;
  573.     unsigned int enabled;
  574.     uint32_t old_mask;
  575.     int ret = -1;
  576.  
  577.     /* skip out immediately if the cache is disabled */
  578.     PINT_tcache_get_info(static_acache, TCACHE_ENABLE, &enabled);
  579.     if(!enabled)
  580.     {
  581.         return(0);
  582.     }
  583.     
  584.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: update(): H=%llu\n",
  585.                  llu(refn.handle));
  586.   
  587.     if(!attr && !size)
  588.     {
  589.         return(-PVFS_EINVAL);
  590.     }
  591.  
  592.     /* do we have static fields? */
  593.     if(attr && (attr->mask & PVFS_STATIC_ATTR_MASK))
  594.     {
  595.         tmp_static_payload = 
  596.             (struct static_payload*)calloc(1, sizeof(*tmp_static_payload));
  597.         if(!tmp_static_payload)
  598.         {
  599.             ret = -PVFS_ENOMEM;
  600.             goto err;
  601.         }
  602.         tmp_static_payload->refn = refn;
  603.         tmp_static_payload->mask = attr->mask & PVFS_STATIC_ATTR_MASK;
  604.         if(attr->mask & PVFS_ATTR_COMMON_TYPE)
  605.         {
  606.             tmp_static_payload->objtype = attr->objtype;
  607.         }
  608.         if(attr->mask & PVFS_ATTR_META_DFILES)
  609.         {
  610.             tmp_static_payload->dfile_array = 
  611.                 malloc(attr->u.meta.dfile_count*sizeof(PVFS_handle));
  612.             if(!tmp_static_payload->dfile_array)
  613.             {
  614.                 ret = -PVFS_ENOMEM;
  615.                 goto err;
  616.             }
  617.             memcpy(tmp_static_payload->dfile_array, attr->u.meta.dfile_array,
  618.                 attr->u.meta.dfile_count*sizeof(PVFS_handle));
  619.             tmp_static_payload->dfile_count = attr->u.meta.dfile_count;
  620.         }
  621.         if(attr->mask & PVFS_ATTR_META_MIRROR_DFILES)
  622.         {
  623.            tmp_static_payload->mirror_dfile_array =
  624.                 malloc(attr->u.meta.dfile_count * sizeof(PVFS_handle) *
  625.                        attr->u.meta.mirror_copies_count);
  626.            if (!tmp_static_payload->mirror_dfile_array)
  627.            {
  628.                 ret = -PVFS_ENOMEM;
  629.                 goto err;
  630.            }
  631.            memcpy(tmp_static_payload->mirror_dfile_array
  632.                  ,attr->u.meta.mirror_dfile_array
  633.                  ,attr->u.meta.dfile_count * sizeof(PVFS_handle) *
  634.                   attr->u.meta.mirror_copies_count);
  635.            tmp_static_payload->mirror_copies_count =
  636.                 attr->u.meta.mirror_copies_count;
  637.         }
  638.         if(attr->mask & PVFS_ATTR_META_DIST)
  639.         {
  640.             tmp_static_payload->dist = PINT_dist_copy(attr->u.meta.dist);
  641.             if(!tmp_static_payload->dist)
  642.             {
  643.                 ret = -PVFS_ENOMEM;
  644.                 goto err;
  645.             }
  646.             tmp_static_payload->dist_size = attr->u.meta.dist_size;
  647.         }
  648.     }
  649.  
  650.     /* do we have size or other non-static fields? */
  651.     if(size || (attr && (attr->mask & (~(PVFS_STATIC_ATTR_MASK)))))
  652.     {
  653.         tmp_payload = 
  654.             (struct acache_payload*)calloc(1, sizeof(*tmp_payload));
  655.         if(!tmp_payload)
  656.         {
  657.             ret = -PVFS_ENOMEM;
  658.             goto err;
  659.         }
  660.         tmp_payload->refn = refn;
  661.         tmp_payload->attr_status = -PVFS_ETIME;
  662.         tmp_payload->size_status = -PVFS_ETIME;
  663.  
  664.         if(attr && (attr->mask & (~(PVFS_STATIC_ATTR_MASK))))
  665.         {
  666.             /* modify mask temporarily so that we only copy non-static fields
  667.              * here
  668.              */
  669.             old_mask = attr->mask;
  670.             attr->mask = (attr->mask & (~(PVFS_STATIC_ATTR_MASK)));
  671.             ret = PINT_copy_object_attr(&(tmp_payload->attr), attr);
  672.             if(ret < 0)
  673.             {
  674.                 goto err;
  675.             }
  676.             tmp_payload->attr_status = 0;
  677.             attr->mask = old_mask;
  678.         }
  679.       
  680.         if(size)
  681.         {
  682.             tmp_payload->size = *size;
  683.             tmp_payload->size_status = 0;
  684.         }
  685.  
  686.     }
  687.    
  688. #if 0
  689.     gossip_debug(GOSSIP_ACACHE_DEBUG, "acache: update(): attr_status=%d, size_status=%d\n",
  690.                  tmp_payload->attr_status, tmp_payload->size_status);
  691. #endif
  692.  
  693.     gen_mutex_lock(&acache_mutex);
  694.  
  695.     if(tmp_static_payload)
  696.     {
  697.         load_payload(static_acache, refn, tmp_static_payload, static_pc);
  698.     }
  699.     if(tmp_payload)
  700.     {
  701.         load_payload(acache, refn, tmp_payload, acache_pc);
  702.     }
  703.  
  704.     gen_mutex_unlock(&acache_mutex);
  705.   
  706.     return(0);
  707.  
  708. err:
  709.  
  710.     if(tmp_static_payload)
  711.     {
  712.         if(tmp_static_payload->dfile_array)
  713.             free(tmp_static_payload->dfile_array);
  714.         if(tmp_static_payload->mirror_dfile_array)
  715.             free(tmp_static_payload->mirror_dfile_array);
  716.         if(tmp_static_payload->dist)
  717.             PINT_dist_free(tmp_static_payload->dist);
  718.         free(tmp_static_payload);
  719.     }
  720.     if(tmp_payload)
  721.     {
  722.         PINT_free_object_attr(&tmp_payload->attr);
  723.         free(tmp_payload);
  724.     }
  725.     
  726.     return(ret);
  727. }
  728.   
  729. /* static_compare_key_entry()
  730.  *
  731.  * compares an opaque key (object ref in this case) against a payload to see
  732.  * if there is a match
  733.  *
  734.  * returns 1 on match, 0 otherwise
  735.  */
  736. static int static_compare_key_entry(void* key, struct qhash_head* link)
  737. {
  738.     PVFS_object_ref* real_key = (PVFS_object_ref*)key;
  739.     struct static_payload* tmp_payload = NULL;
  740.     struct PINT_tcache_entry* tmp_entry = NULL;
  741.   
  742.     tmp_entry = qhash_entry(link, struct PINT_tcache_entry, hash_link);
  743.     assert(tmp_entry);
  744.   
  745.     tmp_payload = (struct static_payload*)tmp_entry->payload;
  746.     if(real_key->handle == tmp_payload->refn.handle &&
  747.        real_key->fs_id == tmp_payload->refn.fs_id)
  748.     {
  749.         return(1);
  750.     }
  751.   
  752.     return(0);
  753. }
  754.  
  755. /* acache_compare_key_entry()
  756.  *
  757.  * compares an opaque key (object ref in this case) against a payload to see
  758.  * if there is a match
  759.  *
  760.  * returns 1 on match, 0 otherwise
  761.  */
  762. static int acache_compare_key_entry(void* key, struct qhash_head* link)
  763. {
  764.     PVFS_object_ref* real_key = (PVFS_object_ref*)key;
  765.     struct acache_payload* tmp_payload = NULL;
  766.     struct PINT_tcache_entry* tmp_entry = NULL;
  767.   
  768.     tmp_entry = qhash_entry(link, struct PINT_tcache_entry, hash_link);
  769.     assert(tmp_entry);
  770.   
  771.     tmp_payload = (struct acache_payload*)tmp_entry->payload;
  772.     if(real_key->handle == tmp_payload->refn.handle &&
  773.        real_key->fs_id == tmp_payload->refn.fs_id)
  774.     {
  775.         return(1);
  776.     }
  777.   
  778.     return(0);
  779. }
  780.   
  781. /* acache_hash_key()
  782.  *
  783.  * hash function for object references
  784.  *
  785.  * returns hash index 
  786.  */
  787. static int acache_hash_key(void* key, int table_size)
  788. {
  789.     PVFS_object_ref* real_key = (PVFS_object_ref*)key;
  790.     int tmp_ret = 0;
  791.  
  792.     tmp_ret = (real_key->handle)%table_size;
  793.     return(tmp_ret);
  794. }
  795.   
  796. /* static_free_payload()
  797.  *
  798.  * frees payload that has been stored in the acache 
  799.  *
  800.  * returns 0 on success, -PVFS_error on failure
  801.  */
  802. static int static_free_payload(void* payload)
  803. {
  804.     struct static_payload* tmp_static_payload = 
  805.         (struct static_payload*)payload;
  806.   
  807.     if(tmp_static_payload->dfile_array)
  808.     {
  809.         free(tmp_static_payload->dfile_array);
  810.     }
  811.     if(tmp_static_payload->mirror_dfile_array)
  812.     {
  813.         free(tmp_static_payload->mirror_dfile_array);
  814.     }
  815.     if(tmp_static_payload->dist)
  816.     {
  817.         PINT_dist_free(tmp_static_payload->dist);
  818.     }
  819.     free(tmp_static_payload);
  820.     return(0);
  821.  
  822. }
  823.  
  824. /* acache_free_payload()
  825.  *
  826.  * frees payload that has been stored in the acache 
  827.  *
  828.  * returns 0 on success, -PVFS_error on failure
  829.  */
  830. static int acache_free_payload(void* payload)
  831. {
  832.     struct acache_payload* tmp_payload = (struct acache_payload*)payload;
  833.   
  834.     PINT_free_object_attr(&tmp_payload->attr);
  835.     free(tmp_payload);
  836.     return(0);
  837.  
  838. }
  839.  
  840.  
  841. static int set_tcache_defaults(struct PINT_tcache* instance)
  842. {
  843.     int ret;
  844.  
  845.     ret = PINT_tcache_set_info(instance, TCACHE_HARD_LIMIT, 
  846.                                ACACHE_DEFAULT_HARD_LIMIT);
  847.     if(ret < 0)
  848.     {
  849.         return(ret);
  850.     }
  851.     ret = PINT_tcache_set_info(instance, TCACHE_SOFT_LIMIT, 
  852.                                ACACHE_DEFAULT_SOFT_LIMIT);
  853.     if(ret < 0)
  854.     {
  855.         return(ret);
  856.     }
  857.     ret = PINT_tcache_set_info(instance, TCACHE_RECLAIM_PERCENTAGE,
  858.                                ACACHE_DEFAULT_RECLAIM_PERCENTAGE);
  859.     if(ret < 0)
  860.     {
  861.         return(ret);
  862.     }
  863.  
  864.     return(0);
  865. }
  866.  
  867. static void load_payload(struct PINT_tcache* instance, 
  868.     PVFS_object_ref refn,
  869.     void* payload,
  870.     struct PINT_perf_counter* pc)
  871. {
  872.     int status;
  873.     int purged;
  874.     struct PINT_tcache_entry* tmp_entry;
  875.     int ret;
  876.  
  877.     /* find out if the entry is already in the cache */
  878.     ret = PINT_tcache_lookup(instance, 
  879.                              &refn,
  880.                              &tmp_entry,
  881.                              &status);
  882.     if(ret == 0)
  883.     {
  884.         /* found match in cache; destroy old payload, replace, and
  885.          * refresh time stamp
  886.          */
  887.         instance->free_payload(tmp_entry->payload);
  888.         tmp_entry->payload = payload;
  889.         ret = PINT_tcache_refresh_entry(instance, tmp_entry);
  890.         /* this counts as an update of an existing entry */
  891.         PINT_perf_count(pc, PERF_ACACHE_UPDATES, 1, PINT_PERF_ADD);
  892.     }
  893.     else
  894.     {
  895.         /* not found in cache; insert new payload*/
  896.         ret = PINT_tcache_insert_entry(instance, 
  897.             &refn, payload, &purged);
  898.         /* the purged variable indicates how many entries had to be purged
  899.          * from the tcache to make room for this new one
  900.          */
  901.         if(purged == 1)
  902.         {
  903.             /* since only one item was purged, we count this as one item being
  904.              * replaced rather than as a purge and an insert 
  905.              */
  906.             PINT_perf_count(pc, PERF_ACACHE_REPLACEMENTS, purged, 
  907.                 PINT_PERF_ADD);
  908.         }
  909.         else
  910.         {
  911.             /* otherwise we just purged as part of reclaimation */
  912.             /* if we didn't purge anything, then the "purged" variable will
  913.              * be zero and this counter call won't do anything.
  914.              */
  915.             PINT_perf_count(pc, PERF_ACACHE_PURGES, purged,
  916.                 PINT_PERF_ADD);
  917.         }
  918.     }
  919.     PINT_perf_count(pc, PERF_ACACHE_NUM_ENTRIES,
  920.         instance->num_entries, PINT_PERF_SET);
  921.     return;
  922. }
  923.  
  924. /*
  925.  * Local variables:
  926.  *  c-indent-level: 4
  927.  *  c-basic-offset: 4
  928.  * End:
  929.  *
  930.  * vim: ts=8 sts=4 sw=4 expandtab
  931.  */
  932.  
  933.