CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cvmfs_cache_null.cc
Go to the documentation of this file.
1 
8 #define __STDC_FORMAT_MACROS
9 
10 #include <alloca.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <stdint.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 
18 #include <cassert>
19 #include <cstdio>
20 #include <cstring>
21 #include <ctime>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include "libcvmfs_cache.h"
27 
28 using namespace std; // NOLINT
29 
30 struct Object {
31  struct cvmcache_hash id;
32  string data;
34  int32_t refcnt;
35  string description;
36 };
37 
38 struct TxnInfo {
39  struct cvmcache_hash id;
41 };
42 
43 struct Listing {
44  Listing() : type(CVMCACHE_OBJECT_REGULAR), pos(0), elems(NULL) { }
46  uint64_t pos;
47  vector<Object> *elems;
48 };
49 
51  ComparableHash() { memset(&hash, 0, sizeof(hash)); }
52  explicit ComparableHash(const struct cvmcache_hash &h) : hash(h) { }
53  struct cvmcache_hash hash;
54  bool operator<(const ComparableHash &other) const {
55  return cvmcache_hash_cmp(const_cast<cvmcache_hash *>(&(this->hash)),
56  const_cast<cvmcache_hash *>(&(other.hash)))
57  < 0;
58  }
59 };
60 
61 map<uint64_t, TxnInfo> transactions;
62 map<ComparableHash, Object> storage;
63 map<uint64_t, Listing> listings;
64 map<std::string, cvmcache_breadcrumb> breadcrumbs;
65 
67 
68 static int null_chrefcnt(struct cvmcache_hash *id, int32_t change_by) {
69  ComparableHash h(*id);
70  if (storage.find(h) == storage.end())
72 
73  Object obj = storage[h];
74  obj.refcnt += change_by;
75  if (obj.refcnt < 0)
77  storage[h] = obj;
78  return CVMCACHE_STATUS_OK;
79 }
80 
81 
82 static int null_obj_info(struct cvmcache_hash *id,
83  struct cvmcache_object_info *info) {
84  ComparableHash h(*id);
85  if (storage.find(h) == storage.end())
87 
88  Object obj = storage[h];
89  info->size = obj.data.length();
90  info->type = obj.type;
91  info->pinned = obj.refcnt > 0;
92  info->description = strdup(obj.description.c_str());
93  return CVMCACHE_STATUS_OK;
94 }
95 
96 
97 static int null_pread(struct cvmcache_hash *id,
98  uint64_t offset,
99  uint32_t *size,
100  unsigned char *buffer) {
101  ComparableHash h(*id);
102  string data = storage[h].data;
103  if (offset > data.length())
105  unsigned nbytes = std::min(*size,
106  static_cast<uint32_t>(data.length() - offset));
107  memcpy(buffer, data.data() + offset, nbytes);
108  *size = nbytes;
109  return CVMCACHE_STATUS_OK;
110 }
111 
112 
113 static int null_start_txn(struct cvmcache_hash *id,
114  uint64_t txn_id,
115  struct cvmcache_object_info *info) {
116  Object partial_object;
117  partial_object.id = *id;
118  partial_object.type = info->type;
119  partial_object.refcnt = 1;
120  if (info->description != NULL)
121  partial_object.description = string(info->description);
122  TxnInfo txn;
123  txn.id = *id;
124  txn.partial_object = partial_object;
125  transactions[txn_id] = txn;
126  return CVMCACHE_STATUS_OK;
127 }
128 
129 
130 static int null_write_txn(uint64_t txn_id,
131  unsigned char *buffer,
132  uint32_t size) {
133  TxnInfo txn = transactions[txn_id];
134  txn.partial_object.data += string(reinterpret_cast<char *>(buffer), size);
135  transactions[txn_id] = txn;
136  return CVMCACHE_STATUS_OK;
137 }
138 
139 
140 static int null_commit_txn(uint64_t txn_id) {
141  TxnInfo txn = transactions[txn_id];
142  ComparableHash h(txn.id);
143  storage[h] = txn.partial_object;
144  transactions.erase(txn_id);
145  return CVMCACHE_STATUS_OK;
146 }
147 
148 static int null_abort_txn(uint64_t txn_id) {
149  transactions.erase(txn_id);
150  return CVMCACHE_STATUS_OK;
151 }
152 
153 static int null_info(struct cvmcache_info *info) {
154  info->size_bytes = uint64_t(-1);
155  info->used_bytes = info->pinned_bytes = 0;
156  for (map<ComparableHash, Object>::const_iterator i = storage.begin(),
157  i_end = storage.end();
158  i != i_end;
159  ++i) {
160  info->used_bytes += i->second.data.length();
161  if (i->second.refcnt > 0)
162  info->pinned_bytes += i->second.data.length();
163  }
164  info->no_shrink = 0;
165  return CVMCACHE_STATUS_OK;
166 }
167 
168 static int null_shrink(uint64_t shrink_to, uint64_t *used) {
169  struct cvmcache_info info;
170  null_info(&info);
171  *used = info.used_bytes;
172  if (info.used_bytes <= shrink_to)
173  return CVMCACHE_STATUS_OK;
174 
175  // Volatile objects
176  for (map<ComparableHash, Object>::iterator i = storage.begin(),
177  i_end = storage.end();
178  i != i_end;) {
179  if ((i->second.refcnt > 0)
180  || (i->second.type != CVMCACHE_OBJECT_VOLATILE)) {
181  ++i;
182  continue;
183  }
184  unsigned length = i->second.data.length();
185  map<ComparableHash, Object>::iterator delete_me = i++;
186  storage.erase(delete_me);
187  info.used_bytes -= length;
188  if (info.used_bytes <= shrink_to) {
189  *used = info.used_bytes;
190  return CVMCACHE_STATUS_OK;
191  }
192  }
193  // All other objects
194  for (map<ComparableHash, Object>::iterator i = storage.begin(),
195  i_end = storage.end();
196  i != i_end;) {
197  if (i->second.refcnt > 0) {
198  ++i;
199  continue;
200  }
201  unsigned length = i->second.data.length();
202  map<ComparableHash, Object>::iterator delete_me = i++;
203  storage.erase(delete_me);
204  info.used_bytes -= length;
205  if (info.used_bytes <= shrink_to) {
206  *used = info.used_bytes;
207  return CVMCACHE_STATUS_OK;
208  }
209  }
210 
211  *used = info.used_bytes;
213 }
214 
215 static int null_listing_begin(uint64_t lst_id, enum cvmcache_object_type type) {
216  Listing lst;
217  lst.type = type;
218  lst.elems = new vector<Object>();
219  for (map<ComparableHash, Object>::const_iterator i = storage.begin(),
220  i_end = storage.end();
221  i != i_end;
222  ++i) {
223  lst.elems->push_back(i->second);
224  }
225  listings[lst_id] = lst;
226  return CVMCACHE_STATUS_OK;
227 }
228 
229 static int null_listing_next(int64_t listing_id,
230  struct cvmcache_object_info *item) {
231  Listing lst = listings[listing_id];
232  do {
233  if (lst.pos >= lst.elems->size())
235 
236  vector<Object> *elems = lst.elems;
237  if ((*elems)[lst.pos].type == lst.type) {
238  item->id = (*elems)[lst.pos].id;
239  item->size = (*elems)[lst.pos].data.length();
240  item->type = (*elems)[lst.pos].type;
241  item->pinned = (*elems)[lst.pos].refcnt > 0;
242  item->description = (*elems)[lst.pos].description.empty()
243  ? NULL
244  : strdup((*elems)[lst.pos].description.c_str());
245  break;
246  }
247  lst.pos++;
248  } while (true);
249  lst.pos++;
250  listings[listing_id] = lst;
251  return CVMCACHE_STATUS_OK;
252 }
253 
254 static int null_listing_end(int64_t listing_id) {
255  delete listings[listing_id].elems;
256  listings.erase(listing_id);
257  return CVMCACHE_STATUS_OK;
258 }
259 
260 static int null_breadcrumb_store(const char *fqrn,
261  const cvmcache_breadcrumb *breadcrumb) {
262  breadcrumbs[fqrn] = *breadcrumb;
263  return CVMCACHE_STATUS_OK;
264 }
265 
266 static int null_breadcrumb_load(const char *fqrn,
267  cvmcache_breadcrumb *breadcrumb) {
268  map<std::string, cvmcache_breadcrumb>::const_iterator itr = breadcrumbs.find(
269  fqrn);
270  if (itr == breadcrumbs.end())
272  *breadcrumb = itr->second;
273  return CVMCACHE_STATUS_OK;
274 }
275 
276 static void Usage(const char *progname) {
277  printf("%s <config file>\n", progname);
278 }
279 
280 
281 int main(int argc, char **argv) {
282  if (argc < 2) {
283  Usage(argv[0]);
284  return 1;
285  }
286 
288 
290  if (cvmcache_options_parse(options, argv[1]) != 0) {
291  printf("cannot parse options file %s\n", argv[1]);
292  return 1;
293  }
294  char *locator = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_LOCATOR");
295  if (locator == NULL) {
296  printf("CVMFS_CACHE_PLUGIN_LOCATOR missing\n");
297  cvmcache_options_fini(options);
298  return 1;
299  }
300  char *test_mode = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_TEST");
301 
302  if (!test_mode)
304 
305  struct cvmcache_callbacks callbacks;
306  memset(&callbacks, 0, sizeof(callbacks));
307  callbacks.cvmcache_chrefcnt = null_chrefcnt;
308  callbacks.cvmcache_obj_info = null_obj_info;
309  callbacks.cvmcache_pread = null_pread;
314  callbacks.cvmcache_info = null_info;
315  callbacks.cvmcache_shrink = null_shrink;
321  callbacks.capabilities = CVMCACHE_CAP_ALL_V2;
322 
323  ctx = cvmcache_init(&callbacks);
324  int retval = cvmcache_listen(ctx, locator);
325  if (!retval) {
326  fprintf(stderr, "failed to listen on %s\n", locator);
327  return 1;
328  }
329 
330  if (test_mode) {
331  // Daemonize, print out PID
332  pid_t pid;
333  int statloc;
334  if ((pid = fork()) == 0) {
335  if ((pid = fork()) == 0) {
336  int null_read = open("/dev/null", O_RDONLY);
337  int null_write = open("/dev/null", O_WRONLY);
338  assert((null_read >= 0) && (null_write >= 0));
339  int retval = dup2(null_read, 0);
340  assert(retval == 0);
341  retval = dup2(null_write, 1);
342  assert(retval == 1);
343  retval = dup2(null_write, 2);
344  assert(retval == 2);
345  close(null_read);
346  close(null_write);
347  } else {
348  assert(pid > 0);
349  printf("%d\n", pid);
350  fflush(stdout);
351  fsync(1);
352  _exit(0);
353  }
354  } else {
355  assert(pid > 0);
356  waitpid(pid, &statloc, 0);
357  _exit(0);
358  }
359  }
360 
361  printf("Listening for cvmfs clients on %s\n", locator);
362  printf("NOTE: this process needs to run as user cvmfs\n\n");
363 
364  // Starts the I/O processing thread
366 
367  if (test_mode)
368  while (true)
369  sleep(1);
370 
371  if (!cvmcache_is_supervised()) {
372  printf("Press <R ENTER> to ask clients to release nested catalogs\n");
373  printf("Press <Ctrl+D> to quit\n");
374  while (true) {
375  char buf;
376  int retval = read(fileno(stdin), &buf, 1);
377  if (retval != 1)
378  break;
379  if (buf == 'R') {
380  printf(" ... asking clients to release nested catalogs\n");
382  }
383  }
385  }
386 
388  printf(" ... good bye\n");
389 
390  cvmcache_options_free(locator);
391  cvmcache_options_fini(options);
394  return 0;
395 }
static int null_write_txn(uint64_t txn_id, unsigned char *buffer, uint32_t size)
static int null_chrefcnt(struct cvmcache_hash *id, int32_t change_by)
int(* cvmcache_chrefcnt)(struct cvmcache_hash *id, int32_t change_by)
struct cvmcache_hash id
struct cvmcache_context * ctx
static int null_pread(struct cvmcache_hash *id, uint64_t offset, uint32_t *size, unsigned char *buffer)
struct cvmcache_hash hash
cvmcache_object_type
int(* cvmcache_info)(struct cvmcache_info *info)
static void Usage(const char *progname)
void cvmcache_terminate(struct cvmcache_context *ctx)
int cvmcache_listen(struct cvmcache_context *ctx, char *locator)
struct cvmcache_hash id
int(* cvmcache_listing_next)(int64_t lst_id, struct cvmcache_object_info *item)
void cvmcache_cleanup_global()
void cvmcache_terminate_watchdog()
string description
static int null_listing_begin(uint64_t lst_id, enum cvmcache_object_type type)
static int null_breadcrumb_store(const char *fqrn, const cvmcache_breadcrumb *breadcrumb)
assert((mem||(size==0))&&"Out Of Memory")
uint64_t pinned_bytes
int cvmcache_is_supervised()
map< uint64_t, TxnInfo > transactions
static int null_info(struct cvmcache_info *info)
int(* cvmcache_pread)(struct cvmcache_hash *id, uint64_t offset, uint32_t *size, unsigned char *buffer)
map< std::string, cvmcache_breadcrumb > breadcrumbs
int(* cvmcache_breadcrumb_load)(const char *fqrn, cvmcache_breadcrumb *breadcrumb)
static int null_start_txn(struct cvmcache_hash *id, uint64_t txn_id, struct cvmcache_object_info *info)
map< ComparableHash, Object > storage
void cvmcache_wait_for(struct cvmcache_context *ctx)
uint64_t used_bytes
int main()
Definition: helper_allow.cc:16
Object partial_object
static int null_listing_end(int64_t listing_id)
static int null_shrink(uint64_t shrink_to, uint64_t *used)
static int null_breadcrumb_load(const char *fqrn, cvmcache_breadcrumb *breadcrumb)
void cvmcache_ask_detach(struct cvmcache_context *ctx)
int(* cvmcache_write_txn)(uint64_t txn_id, unsigned char *buffer, uint32_t size)
map< uint64_t, Listing > listings
uint64_t pos
int cvmcache_hash_cmp(struct cvmcache_hash *a, struct cvmcache_hash *b)
cvmcache_object_type type
void cvmcache_options_free(char *value)
void cvmcache_spawn_watchdog(const char *crash_dump_file)
void cvmcache_options_fini(cvmcache_option_map *opts)
uint64_t size_bytes
enum cvmcache_object_type type
struct cvmcache_context * cvmcache_init(struct cvmcache_callbacks *callbacks)
void cvmcache_init_global()
vector< Object > * elems
int cvmcache_options_parse(cvmcache_option_map *opts, const char *path)
int(* cvmcache_shrink)(uint64_t shrink_to, uint64_t *used)
static int null_obj_info(struct cvmcache_hash *id, struct cvmcache_object_info *info)
int32_t refcnt
int(* cvmcache_listing_begin)(uint64_t lst_id, enum cvmcache_object_type type)
void cvmcache_process_requests(struct cvmcache_context *ctx, unsigned nworkers)
int(* cvmcache_breadcrumb_store)(const char *fqrn, const cvmcache_breadcrumb *breadcrumb)
char * cvmcache_options_get(cvmcache_option_map *opts, const char *key)
cvmcache_object_type type
int(* cvmcache_commit_txn)(uint64_t txn_id)
int(* cvmcache_start_txn)(struct cvmcache_hash *id, uint64_t txn_id, struct cvmcache_object_info *info)
int(* cvmcache_listing_end)(int64_t lst_id)
int(* cvmcache_abort_txn)(uint64_t txn_id)
string data
ComparableHash(const struct cvmcache_hash &h)
static int null_abort_txn(uint64_t txn_id)
struct cvmcache_hash id
int(* cvmcache_obj_info)(struct cvmcache_hash *id, struct cvmcache_object_info *info)
static void size_t size
Definition: smalloc.h:54
static int null_listing_next(int64_t listing_id, struct cvmcache_object_info *item)
static int null_commit_txn(uint64_t txn_id)
cvmcache_option_map * cvmcache_options_init()
bool operator<(const ComparableHash &other) const