root/branches/Orange-Elaine-Distr-Dir-Branch/src/client/sysint/acache.c @ 8596

Revision 8596, 27.6 KB (checked in by shuangy, 3 years ago)

1. fix two memory leaks in fee_object_attr and decode_release. 2. clean sys-mkdir and acache.

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