glusterfs  8.2
About: GlusterFS is a network/cluster filesystem. The storage server (or each in a cluster) runs glusterfsd and the clients use mount command or glusterfs client to mount the exported filesystem. Release series 8.x (latest version).
  Fossies Dox: glusterfs-8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

gidcache.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3  This file is part of GlusterFS.
4 
5  This file is licensed to you under your choice of the GNU Lesser
6  General Public License, version 3 or any later version (LGPLv3 or
7  later), or the GNU General Public License, version 2 (GPLv2), in all
8  cases as published by the Free Software Foundation.
9 */
10 
11 #include "glusterfs/gidcache.h"
12 #include "glusterfs/mem-pool.h"
13 
14 /*
15  * We treat this as a very simple set-associative LRU cache, with entries aged
16  * out after a configurable interval. Hardly rocket science, but lots of
17  * details to worry about.
18  */
19 #define BUCKET_START(p, n) ((p) + ((n)*AUX_GID_CACHE_ASSOC))
20 
21 /*
22  * Initialize the cache.
23  */
24 int
25 gid_cache_init(gid_cache_t *cache, uint32_t timeout)
26 {
27  if (!cache)
28  return -1;
29 
30  LOCK_INIT(&cache->gc_lock);
31  cache->gc_max_age = timeout;
33  memset(cache->gc_cache, 0, sizeof(gid_list_t) * AUX_GID_CACHE_SIZE);
34 
35  return 0;
36 }
37 
38 /*
39  * Reconfigure the cache timeout.
40  */
41 int
42 gid_cache_reconf(gid_cache_t *cache, uint32_t timeout)
43 {
44  if (!cache)
45  return -1;
46 
47  LOCK(&cache->gc_lock);
48  cache->gc_max_age = timeout;
49  UNLOCK(&cache->gc_lock);
50 
51  return 0;
52 }
53 
54 /*
55  * Look up an ID in the cache. If found, return the actual cache entry to avoid
56  * an additional allocation and memory copy. The caller should copy the data and
57  * release (unlock) the cache as soon as possible.
58  */
59 const gid_list_t *
60 gid_cache_lookup(gid_cache_t *cache, uint64_t id, uint64_t uid, uint64_t gid)
61 {
62  int bucket;
63  int i;
64  time_t now;
65  const gid_list_t *agl;
66 
67  now = time(NULL);
68  LOCK(&cache->gc_lock);
69  bucket = id % cache->gc_nbuckets;
70  agl = BUCKET_START(cache->gc_cache, bucket);
71  for (i = 0; i < AUX_GID_CACHE_ASSOC; i++, agl++) {
72  if (!agl->gl_list)
73  continue;
74  if (agl->gl_id != id)
75  continue;
76 
77  /*
78  @uid and @gid reflect the latest UID/GID of the
79  process performing the syscall (taken from frame->root).
80 
81  If the UID and GID has changed for the PID since the
82  time we cached it, we should treat the cache as having
83  stale values and query them freshly.
84  */
85  if (agl->gl_uid != uid || agl->gl_gid != gid)
86  break;
87 
88  /*
89  * We don't put new entries in the cache when expiration=0, but
90  * there might be entries still in there if expiration was
91  * changed very recently. Writing the check this way ensures
92  * that they're not used.
93  */
94  if (now < agl->gl_deadline) {
95  return agl;
96  }
97 
98  /*
99  * We're not going to find any more UID matches, and reaping
100  * is handled further down to maintain LRU order.
101  */
102  break;
103  }
104  UNLOCK(&cache->gc_lock);
105  return NULL;
106 }
107 
108 /*
109  * Release an entry found via lookup.
110  */
111 void
113 {
114  UNLOCK(&cache->gc_lock);
115 }
116 
117 /*
118  * Add a new list entry to the cache. If an entry for this ID already exists,
119  * update it.
120  */
121 int
123 {
124  gid_list_t *agl;
125  int bucket;
126  int i;
127  time_t now;
128 
129  if (!gl || !gl->gl_list)
130  return -1;
131 
132  if (!cache->gc_max_age)
133  return 0;
134 
135  now = time(NULL);
136  LOCK(&cache->gc_lock);
137 
138  /*
139  * Scan for the first free entry or one that matches this id. The id
140  * check is added to address a bug where the cache might contain an
141  * expired entry for this id. Since lookup occurs in LRU order and
142  * does not reclaim entries, it will always return failure on discovery
143  * of an expired entry. This leads to duplicate entries being added,
144  * which still do not satisfy lookups until the expired entry (and
145  * everything before it) is reclaimed.
146  *
147  * We address this through reuse of an entry already allocated to this
148  * id, whether expired or not, since we have obviously already received
149  * more recent data. The entry is repopulated with the new data and a new
150  * deadline and is pushed forward to reside as the last populated entry in
151  * the bucket.
152  */
153  bucket = gl->gl_id % cache->gc_nbuckets;
154  agl = BUCKET_START(cache->gc_cache, bucket);
155  for (i = 0; i < AUX_GID_CACHE_ASSOC; ++i, ++agl) {
156  if (agl->gl_id == gl->gl_id)
157  break;
158  if (!agl->gl_list)
159  break;
160  }
161 
162  /*
163  * The way we allocate free entries naturally places the newest
164  * ones at the highest indices, so evicting the lowest makes
165  * sense, but that also means we can't just replace it with the
166  * one that caused the eviction. That would cause us to thrash
167  * the first entry while others remain idle. Therefore, we
168  * need to slide the other entries down and add the new one at
169  * the end just as if the *last* slot had been free.
170  *
171  * Deadline expiration is also handled here, since the oldest
172  * expired entry will be in the first position. This does mean
173  * the bucket can stay full of expired entries if we're idle
174  * but, if the small amount of extra memory or scan time before
175  * we decide to evict someone ever become issues, we could
176  * easily add a reaper thread.
177  */
178 
179  if (i >= AUX_GID_CACHE_ASSOC) {
180  /* cache full, evict the first (LRU) entry */
181  i = 0;
182  agl = BUCKET_START(cache->gc_cache, bucket);
183  GF_FREE(agl->gl_list);
184  } else if (agl->gl_list) {
185  /* evict the old entry we plan to reuse */
186  GF_FREE(agl->gl_list);
187  }
188 
189  /*
190  * If we have evicted an entry, slide the subsequent populated entries
191  * back and populate the last entry.
192  */
193  for (; i < AUX_GID_CACHE_ASSOC - 1; i++) {
194  if (!agl[1].gl_list)
195  break;
196  agl[0] = agl[1];
197  agl++;
198  }
199 
200  agl->gl_id = gl->gl_id;
201  agl->gl_uid = gl->gl_uid;
202  agl->gl_gid = gl->gl_gid;
203  agl->gl_count = gl->gl_count;
204  agl->gl_list = gl->gl_list;
205  agl->gl_deadline = now + cache->gc_max_age;
206 
207  UNLOCK(&cache->gc_lock);
208 
209  return 1;
210 }
BUCKET_START
#define BUCKET_START(p, n)
Definition: gidcache.c:19
gid_cache_reconf
int gid_cache_reconf(gid_cache_t *cache, uint32_t timeout)
Definition: gidcache.c:42
mem-pool.h
gid_list_t::gl_id
uint64_t gl_id
Definition: gidcache.h:34
gid_list_t::gl_deadline
time_t gl_deadline
Definition: gidcache.h:39
gid_cache_init
int gid_cache_init(gid_cache_t *cache, uint32_t timeout)
Definition: gidcache.c:25
GF_FREE
#define GF_FREE(free_ptr)
Definition: mem-pool.h:159
gid_list_t::gl_gid
uint64_t gl_gid
Definition: gidcache.h:36
gid_list_t
Definition: gidcache.h:33
gidcache.h
AUX_GID_CACHE_ASSOC
#define AUX_GID_CACHE_ASSOC
Definition: gidcache.h:29
gid_cache_t::gc_nbuckets
unsigned int gc_nbuckets
Definition: gidcache.h:45
UNLOCK
#define UNLOCK(x)
Definition: locking.h:79
gid_cache_t::gc_lock
gf_lock_t gc_lock
Definition: gidcache.h:43
gid_cache_t::gc_max_age
uint32_t gc_max_age
Definition: gidcache.h:44
gid_cache_release
void gid_cache_release(gid_cache_t *cache, const gid_list_t *agl)
Definition: gidcache.c:112
gid_cache_t
Definition: gidcache.h:42
LOCK_INIT
#define LOCK_INIT(x)
Definition: locking.h:76
AUX_GID_CACHE_SIZE
#define AUX_GID_CACHE_SIZE
Definition: gidcache.h:31
AUX_GID_CACHE_BUCKETS
#define AUX_GID_CACHE_BUCKETS
Definition: gidcache.h:30
gid_list_t::gl_count
int gl_count
Definition: gidcache.h:37
gid_list_t::gl_list
gid_t * gl_list
Definition: gidcache.h:38
gid_cache_t::gc_cache
gid_list_t gc_cache[(4 *256)]
Definition: gidcache.h:46
gid_cache_add
int gid_cache_add(gid_cache_t *cache, gid_list_t *gl)
Definition: gidcache.c:122
LOCK
#define LOCK(x)
Definition: locking.h:77
gid_cache_lookup
const gid_list_t * gid_cache_lookup(gid_cache_t *cache, uint64_t id, uint64_t uid, uint64_t gid)
Definition: gidcache.c:60
gid_list_t::gl_uid
uint64_t gl_uid
Definition: gidcache.h:35