IDZEBRA  2.2.7
cfile.c
Go to the documentation of this file.
1 /* This file is part of the Zebra server.
2  Copyright (C) Index Data
3 
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
18 */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <yaz/yaz-util.h>
28 #include <yaz/snprintf.h>
29 #include <idzebra/util.h>
30 #include "mfile.h"
31 #include "cfile.h"
32 
34 #define EXTRA_CHECK 0
35 
36 static int write_head(CFile cf)
37 {
38  int left = cf->head.hash_size * sizeof(zint);
39  int bno = 1;
40  int r = 0;
41  const char *tab = (char*) cf->array;
42 
43  if (!tab)
44  return 0;
45  while (left >= (int) HASH_BSIZE)
46  {
47  r = mf_write(cf->hash_mf, bno++, 0, 0, tab);
48  if (r)
49  return r;
50  tab += HASH_BSIZE;
51  left -= HASH_BSIZE;
52  }
53  if (left > 0)
54  r = mf_write(cf->hash_mf, bno, 0, left, tab);
55  return r;
56 }
57 
58 static int read_head(CFile cf)
59 {
60  int left = cf->head.hash_size * sizeof(zint);
61  int bno = 1;
62  char *tab = (char*) cf->array;
63 
64  if (!tab)
65  return 0;
66  while (left >= (int) HASH_BSIZE)
67  {
68  if (mf_read(cf->hash_mf, bno++, 0, 0, tab) == -1)
69  return -1;
70  tab += HASH_BSIZE;
71  left -= HASH_BSIZE;
72  }
73  if (left > 0)
74  {
75  if (mf_read(cf->hash_mf, bno, 0, left, tab) == -1)
76  return -1;
77  }
78  return 1;
79 }
80 
81 
82 CFile cf_open(MFile mf, MFile_area area, const char *fname,
83  int block_size, int wflag, int *firstp)
84 {
85  char path[1024];
86  int i, ret;
87  CFile cf = (CFile) xmalloc(sizeof(*cf));
88  int hash_bytes;
89 
90  /* avoid valgrind warnings, but set to something nasty */
91  memset(cf, 'Z', sizeof(*cf));
92 
93  yaz_log(YLOG_DEBUG, "cf: open %s %s", fname, wflag ? "rdwr" : "rd");
94 
95  cf->block_mf = 0;
96  cf->hash_mf = 0;
97  cf->rmf = mf;
98 
99  assert(firstp);
100 
101  cf->bucket_lru_front = cf->bucket_lru_back = NULL;
102  cf->bucket_in_memory = 0;
103  cf->max_bucket_in_memory = 100;
104  cf->dirty = 0;
105  cf->iobuf = (char *) xmalloc(block_size);
106  memset(cf->iobuf, 0, block_size);
107  cf->no_hits = 0;
108  cf->no_miss = 0;
109  cf->parray = 0;
110  cf->array = 0;
111  cf->block_mf = 0;
112  cf->hash_mf = 0;
113 
114  zebra_mutex_init(&cf->mutex);
115 
116  yaz_snprintf(path, sizeof(path), "%s-b", fname);
117  if (!(cf->block_mf = mf_open(area, path, block_size, wflag)))
118  {
119  cf_close(cf);
120  return 0;
121  }
122  yaz_snprintf(path, sizeof(path), "%s-i", fname);
123  if (!(cf->hash_mf = mf_open(area, path, HASH_BSIZE, wflag)))
124  {
125  cf_close(cf);
126  return 0;
127  }
128  ret = mf_read(cf->hash_mf, 0, 0, sizeof(cf->head), &cf->head);
129 
130  if (ret == -1)
131  {
132  cf_close(cf);
133  return 0;
134  }
135  if (ret == 0 || !cf->head.state)
136  {
137  *firstp = 1;
139  cf->head.block_size = block_size;
140  cf->head.hash_size = 199;
141  hash_bytes = cf->head.hash_size * sizeof(zint);
143  (hash_bytes+sizeof(cf->head))/HASH_BSIZE + 2;
144  cf->head.next_block = 1;
145  cf->array = (zint *) xmalloc(hash_bytes);
146  for (i = 0; i<cf->head.hash_size; i++)
147  cf->array[i] = 0;
148  if (wflag)
149  {
150  if (mf_write(cf->hash_mf, 0, 0, sizeof(cf->head), &cf->head))
151  {
152  cf_close(cf);
153  return 0;
154  }
155  if (write_head(cf))
156  {
157  cf_close(cf);
158  return 0;
159  }
160  }
161  }
162  else
163  {
164  *firstp = 0;
165  assert(cf->head.block_size == block_size);
166  assert(cf->head.hash_size > 2);
167  hash_bytes = cf->head.hash_size * sizeof(zint);
168  assert(cf->head.next_bucket > 0);
169  assert(cf->head.next_block > 0);
170  if (cf->head.state == CFILE_STATE_HASH)
171  cf->array = (zint *) xmalloc(hash_bytes);
172  else
173  cf->array = NULL;
174  if (read_head(cf) == -1)
175  {
176  cf_close(cf);
177  return 0;
178  }
179  }
180  if (cf->head.state == CFILE_STATE_HASH)
181  {
182  cf->parray = (struct CFile_hash_bucket **)
183  xmalloc(cf->head.hash_size * sizeof(*cf->parray));
184  for (i = 0; i<cf->head.hash_size; i++)
185  cf->parray[i] = NULL;
186  }
187  return cf;
188 }
189 
190 static int cf_hash(CFile cf, zint no)
191 {
192  return (int) (((no >> 3) % cf->head.hash_size));
193 }
194 
195 static void release_bucket(CFile cf, struct CFile_hash_bucket *p)
196 {
197  if (p->lru_prev)
198  p->lru_prev->lru_next = p->lru_next;
199  else
200  cf->bucket_lru_back = p->lru_next;
201  if (p->lru_next)
202  p->lru_next->lru_prev = p->lru_prev;
203  else
204  cf->bucket_lru_front = p->lru_prev;
205 
206  *p->h_prev = p->h_next;
207  if (p->h_next)
208  p->h_next->h_prev = p->h_prev;
209 
210  --(cf->bucket_in_memory);
211  xfree(p);
212 }
213 
214 static int flush_bucket(CFile cf, int no_to_flush)
215 {
216  int i;
217  int ret = 0;
218  struct CFile_hash_bucket *p;
219 
220  for (i = 0; i != no_to_flush; i++)
221  {
222  p = cf->bucket_lru_back;
223  if (!p)
224  break;
225  if (p->dirty)
226  {
227  if (ret == 0)
228  {
229  if (mf_write(cf->hash_mf, p->ph.this_bucket, 0, 0, &p->ph))
230  ret = -1;
231  }
232  cf->dirty = 1;
233  }
234  release_bucket(cf, p);
235  }
236  return ret;
237 }
238 
239 static struct CFile_hash_bucket *alloc_bucket(CFile cf, zint block_no, int hno)
240 {
241  struct CFile_hash_bucket *p, **pp;
242 
243  if (cf->bucket_in_memory == cf->max_bucket_in_memory)
244  {
245  if (flush_bucket(cf, 1))
246  return 0;
247  }
248  assert(cf->bucket_in_memory < cf->max_bucket_in_memory);
249  ++(cf->bucket_in_memory);
250  p = (struct CFile_hash_bucket *) xmalloc(sizeof(*p));
251 
252  p->lru_next = NULL;
253  p->lru_prev = cf->bucket_lru_front;
254  if (cf->bucket_lru_front)
255  cf->bucket_lru_front->lru_next = p;
256  else
257  cf->bucket_lru_back = p;
258  cf->bucket_lru_front = p;
259 
260  pp = cf->parray + hno;
261  p->h_next = *pp;
262  p->h_prev = pp;
263  if (*pp)
264  (*pp)->h_prev = &p->h_next;
265  *pp = p;
266  return p;
267 }
268 
269 static struct CFile_hash_bucket *get_bucket(CFile cf, zint block_no, int hno)
270 {
271  struct CFile_hash_bucket *p;
272 
273  p = alloc_bucket(cf, block_no, hno);
274  if (!p)
275  return 0;
276  p->dirty = 0;
277  if (mf_read(cf->hash_mf, block_no, 0, 0, &p->ph) != 1)
278  {
279  yaz_log(YLOG_FATAL, "read get_bucket");
280  release_bucket(cf, p);
281  return 0;
282  }
283  assert(p->ph.this_bucket == block_no);
284  return p;
285 }
286 
287 static struct CFile_hash_bucket *new_bucket(CFile cf, zint *block_nop, int hno)
288 {
289  struct CFile_hash_bucket *p;
290  int i;
291  zint block_no;
292 
293  block_no = *block_nop = cf->head.next_bucket++;
294  p = alloc_bucket(cf, block_no, hno);
295  if (!p)
296  return 0;
297  p->dirty = 1;
298 
299  for (i = 0; i<HASH_BUCKET; i++)
300  {
301  p->ph.vno[i] = 0;
302  p->ph.no[i] = 0;
303  }
304  p->ph.next_bucket = 0;
305  p->ph.this_bucket = block_no;
306  return p;
307 }
308 
309 static int cf_lookup_flat(CFile cf, zint no, zint *vno)
310 {
311  zint hno = (no*sizeof(zint))/HASH_BSIZE;
312  int off = (int) ((no*sizeof(zint)) - hno*HASH_BSIZE);
313 
314  *vno = 0;
315  if (mf_read(cf->hash_mf, hno+cf->head.next_bucket, off, sizeof(zint), vno)
316  == -1)
317  return -1;
318  if (*vno)
319  return 1;
320  return 0;
321 }
322 
323 static int cf_lookup_hash(CFile cf, zint no, zint *vno)
324 {
325  int hno = cf_hash(cf, no);
326  struct CFile_hash_bucket *hb;
327  zint block_no;
328  int i;
329 
330  for (hb = cf->parray[hno]; hb; hb = hb->h_next)
331  {
332  for (i = 0; i<HASH_BUCKET && hb->ph.vno[i]; i++)
333  if (hb->ph.no[i] == no)
334  {
335  (cf->no_hits)++;
336  *vno = hb->ph.vno[i];
337  return 1;
338  }
339  }
340  for (block_no = cf->array[hno]; block_no; block_no = hb->ph.next_bucket)
341  {
342  for (hb = cf->parray[hno]; hb; hb = hb->h_next)
343  {
344  if (hb->ph.this_bucket == block_no)
345  break;
346  }
347  if (hb)
348  continue;
349 #if EXTRA_CHECK
350  for (hb = cf->bucket_lru_back; hb; hb = hb->lru_next)
351  {
352  if (hb->ph.this_bucket == block_no)
353  {
354  yaz_log(YLOG_FATAL, "Found hash bucket on other chain(1)");
355  return -1;
356  }
357  for (i = 0; i<HASH_BUCKET && hb->ph.vno[i]; i++)
358  if (hb->ph.no[i] == no)
359  {
360  yaz_log(YLOG_FATAL, "Found hash bucket on other chain (2)");
361  return -1;
362  }
363  }
364 #endif
365  (cf->no_miss)++;
366  hb = get_bucket(cf, block_no, hno);
367  if (!hb)
368  return -1;
369  for (i = 0; i<HASH_BUCKET && hb->ph.vno[i]; i++)
370  if (hb->ph.no[i] == no)
371  {
372  *vno = hb->ph.vno[i];
373  return 1;
374  }
375  }
376  return 0;
377 }
378 
379 static int cf_write_flat(CFile cf, zint no, zint vno)
380 {
381  zint hno = (no*sizeof(zint))/HASH_BSIZE;
382  int off = (int) ((no*sizeof(zint)) - hno*HASH_BSIZE);
383 
384  hno += cf->head.next_bucket;
385  if (hno >= cf->head.flat_bucket)
386  cf->head.flat_bucket = hno+1;
387  cf->dirty = 1;
388  return mf_write(cf->hash_mf, hno, off, sizeof(zint), &vno);
389 }
390 
391 static int cf_moveto_flat(CFile cf)
392 {
393  struct CFile_hash_bucket *p;
394  int j;
395  zint i;
396 
397  yaz_log(YLOG_DEBUG, "cf: Moving to flat shadow: %s", cf->rmf->name);
398  yaz_log(YLOG_DEBUG, "cf: hits=%d miss=%d bucket_in_memory=" ZINT_FORMAT " total="
399  ZINT_FORMAT,
400  cf->no_hits, cf->no_miss, cf->bucket_in_memory,
401  cf->head.next_bucket - cf->head.first_bucket);
402  assert(cf->head.state == CFILE_STATE_HASH);
403  if (flush_bucket(cf, -1))
404  return -1;
405  assert(cf->bucket_in_memory == 0);
406  p = (struct CFile_hash_bucket *) xmalloc(sizeof(*p));
407  for (i = cf->head.first_bucket; i < cf->head.next_bucket; i++)
408  {
409  if (mf_read(cf->hash_mf, i, 0, 0, &p->ph) != 1)
410  {
411  yaz_log(YLOG_FATAL|YLOG_ERRNO, "read bucket moveto flat");
412  xfree(p);
413  return -1;
414  }
415  for (j = 0; j < HASH_BUCKET && p->ph.vno[j]; j++)
416  {
417  if (cf_write_flat(cf, p->ph.no[j], p->ph.vno[j]))
418  {
419  xfree(p);
420  return -1;
421  }
422  }
423  }
424  xfree(p);
425  xfree(cf->array);
426  cf->array = NULL;
427  xfree(cf->parray);
428  cf->parray = NULL;
430  cf->dirty = 1;
431  return 0;
432 }
433 
434 static int cf_lookup(CFile cf, zint no, zint *vno)
435 {
436  if (cf->head.state > 1)
437  return cf_lookup_flat(cf, no, vno);
438  return cf_lookup_hash(cf, no, vno);
439 }
440 
441 static zint cf_new_flat(CFile cf, zint no)
442 {
443  zint vno = (cf->head.next_block)++;
444 
445  cf_write_flat(cf, no, vno);
446  return vno;
447 }
448 
449 static zint cf_new_hash(CFile cf, zint no)
450 {
451  int hno = cf_hash(cf, no);
452  struct CFile_hash_bucket *hbprev = NULL, *hb = cf->parray[hno];
453  zint *bucketpp = &cf->array[hno];
454  int i;
455  zint vno = (cf->head.next_block)++;
456 
457  for (hb = cf->parray[hno]; hb; hb = hb->h_next)
458  if (!hb->ph.vno[HASH_BUCKET-1])
459  for (i = 0; i<HASH_BUCKET; i++)
460  if (!hb->ph.vno[i])
461  {
462  (cf->no_hits)++;
463  hb->ph.no[i] = no;
464  hb->ph.vno[i] = vno;
465  hb->dirty = 1;
466  return vno;
467  }
468 
469  while (*bucketpp)
470  {
471  for (hb = cf->parray[hno]; hb; hb = hb->h_next)
472  if (hb->ph.this_bucket == *bucketpp)
473  {
474  bucketpp = &hb->ph.next_bucket;
475  hbprev = hb;
476  break;
477  }
478  if (hb)
479  continue;
480 
481 #if EXTRA_CHECK
482  for (hb = cf->bucket_lru_back; hb; hb = hb->lru_next)
483  {
484  if (hb->ph.this_bucket == *bucketpp)
485  {
486  yaz_log(YLOG_FATAL, "Found hash bucket on other chain");
487  return 0;
488  }
489  }
490 #endif
491  (cf->no_miss)++;
492  hb = get_bucket(cf, *bucketpp, hno);
493  if (!hb)
494  return 0;
495  for (i = 0; i<HASH_BUCKET; i++)
496  if (!hb->ph.vno[i])
497  {
498  hb->ph.no[i] = no;
499  hb->ph.vno[i] = vno;
500  hb->dirty = 1;
501  return vno;
502  }
503  bucketpp = &hb->ph.next_bucket;
504  hbprev = hb;
505  }
506  if (hbprev)
507  hbprev->dirty = 1;
508  hb = new_bucket(cf, bucketpp, hno);
509  if (!hb)
510  return 0;
511 
512  hb->ph.no[0] = no;
513  hb->ph.vno[0] = vno;
514  return vno;
515 }
516 
518 {
519  if (cf->head.state > 1)
520  return cf_new_flat(cf, no);
521  if (cf->no_miss*2 > cf->no_hits)
522  {
523  if (cf_moveto_flat(cf))
524  return -1;
525  assert(cf->head.state > 1);
526  return cf_new_flat(cf, no);
527  }
528  return cf_new_hash(cf, no);
529 }
530 
531 
542 int cf_read(CFile cf, zint no, int offset, int nbytes, void *buf)
543 {
544  zint block;
545  int ret;
546 
547  assert(cf);
548  zebra_mutex_lock(&cf->mutex);
549  ret = cf_lookup(cf, no, &block);
551  if (ret == -1)
552  {
553  /* error */
554  yaz_log(YLOG_FATAL, "cf_lookup failed");
555  return -1;
556  }
557  else if (ret == 0)
558  {
559  /* block could not be read */
560  return ret;
561  }
562  else if (mf_read(cf->block_mf, block, offset, nbytes, buf) != 1)
563  {
564  yaz_log(YLOG_FATAL|YLOG_ERRNO, "mf_read no=" ZINT_FORMAT " block=" ZINT_FORMAT, no, block);
565  return -1;
566  }
567  return 1;
568 }
569 
579 int cf_write(CFile cf, zint no, int offset, int nbytes, const void *buf)
580 {
581  zint block;
582  int ret;
583 
584  assert(cf);
585  zebra_mutex_lock(&cf->mutex);
586 
587  ret = cf_lookup(cf, no, &block);
588 
589  if (ret == -1)
590  {
592  return ret;
593  }
594  if (ret == 0)
595  {
596  block = cf_new(cf, no);
597  if (!block)
598  {
600  return -1;
601  }
602  if (offset || nbytes)
603  {
604  if (mf_read(cf->rmf, no, 0, 0, cf->iobuf) == -1)
605  return -1;
606  memcpy(cf->iobuf + offset, buf, nbytes);
607  buf = cf->iobuf;
608  offset = 0;
609  nbytes = 0;
610  }
611  }
613  return mf_write(cf->block_mf, block, offset, nbytes, buf);
614 }
615 
617 {
618  int ret = 0;
619  yaz_log(YLOG_DEBUG, "cf: close hits=%d miss=%d bucket_in_memory=" ZINT_FORMAT
620  " total=" ZINT_FORMAT,
621  cf->no_hits, cf->no_miss, cf->bucket_in_memory,
622  cf->head.next_bucket - cf->head.first_bucket);
623  if (flush_bucket(cf, -1))
624  ret = -1;
625  if (cf->hash_mf)
626  {
627  if (cf->dirty)
628  {
629  if (mf_write(cf->hash_mf, 0, 0, sizeof(cf->head), &cf->head))
630  ret = -1;
631  if (write_head(cf))
632  ret = -1;
633  }
634  mf_close(cf->hash_mf);
635  }
636  if (cf->block_mf)
637  mf_close(cf->block_mf);
638  xfree(cf->array);
639  xfree(cf->parray);
640  xfree(cf->iobuf);
642  xfree(cf);
643  return ret;
644 }
645 
646 /*
647  * Local variables:
648  * c-basic-offset: 4
649  * c-file-style: "Stroustrup"
650  * indent-tabs-mode: nil
651  * End:
652  * vim: shiftwidth=4 tabstop=8 expandtab
653  */
654 
static zint cf_new_flat(CFile cf, zint no)
Definition: cfile.c:441
CFile cf_open(MFile mf, MFile_area area, const char *fname, int block_size, int wflag, int *firstp)
Definition: cfile.c:82
static int cf_lookup(CFile cf, zint no, zint *vno)
Definition: cfile.c:434
static int cf_write_flat(CFile cf, zint no, zint vno)
Definition: cfile.c:379
static int cf_moveto_flat(CFile cf)
Definition: cfile.c:391
static int read_head(CFile cf)
Definition: cfile.c:58
int cf_read(CFile cf, zint no, int offset, int nbytes, void *buf)
reads block from commit area
Definition: cfile.c:542
static int cf_hash(CFile cf, zint no)
Definition: cfile.c:190
static zint cf_new_hash(CFile cf, zint no)
Definition: cfile.c:449
static struct CFile_hash_bucket * alloc_bucket(CFile cf, zint block_no, int hno)
Definition: cfile.c:239
static int write_head(CFile cf)
Definition: cfile.c:36
zint cf_new(CFile cf, zint no)
Definition: cfile.c:517
static struct CFile_hash_bucket * get_bucket(CFile cf, zint block_no, int hno)
Definition: cfile.c:269
static int cf_lookup_hash(CFile cf, zint no, zint *vno)
Definition: cfile.c:323
int cf_write(CFile cf, zint no, int offset, int nbytes, const void *buf)
writes block to commit area
Definition: cfile.c:579
int cf_close(CFile cf)
Definition: cfile.c:616
static int flush_bucket(CFile cf, int no_to_flush)
Definition: cfile.c:214
static int cf_lookup_flat(CFile cf, zint no, zint *vno)
Definition: cfile.c:309
static void release_bucket(CFile cf, struct CFile_hash_bucket *p)
Definition: cfile.c:195
static struct CFile_hash_bucket * new_bucket(CFile cf, zint *block_nop, int hno)
Definition: cfile.c:287
struct CFile_struct * CFile
All in-memory information per CFile.
#define CFILE_STATE_HASH
state of CFile is a hash structure
Definition: cfile.h:51
#define CFILE_STATE_FLAT
state of CFile is a flat file file
Definition: cfile.h:54
#define HASH_BSIZE
Definition: cfile.h:48
#define HASH_BUCKET
number of blocks in hash bucket
Definition: cfile.h:30
int mf_write(MFile mf, zint no, int offset, int nbytes, const void *buf)
writes block to metafile
Definition: mfile.c:486
int mf_read(MFile mf, zint no, int offset, int nbytes, void *buf)
reads block from metafile
Definition: mfile.c:453
int mf_close(MFile mf)
closes metafile
Definition: mfile.c:431
MFile mf_open(MFile_area ma, const char *name, int block_size, int wflag)
opens metafile
Definition: mfile.c:353
CFile hash structure info in memory.
Definition: cfile.h:41
struct CFile_hash_bucket * lru_next
Definition: cfile.h:45
struct CFile_ph_bucket ph
Definition: cfile.h:42
struct CFile_hash_bucket * h_next
Definition: cfile.h:44
struct CFile_hash_bucket * lru_prev
Definition: cfile.h:45
struct CFile_hash_bucket ** h_prev
Definition: cfile.h:44
int state
Definition: cfile.h:58
zint flat_bucket
Definition: cfile.h:64
int block_size
Definition: cfile.h:60
zint next_block
Definition: cfile.h:59
int hash_size
Definition: cfile.h:61
zint first_bucket
Definition: cfile.h:62
zint next_bucket
Definition: cfile.h:63
zint vno[HASH_BUCKET]
Definition: cfile.h:35
zint this_bucket
Definition: cfile.h:36
zint no[HASH_BUCKET]
Definition: cfile.h:34
zint next_bucket
Definition: cfile.h:37
All in-memory information per CFile.
Definition: cfile.h:69
int no_hits
Definition: cfile.h:83
MFile rmf
Definition: cfile.h:82
struct CFile_hash_bucket ** parray
Definition: cfile.h:75
struct CFile_hash_bucket * bucket_lru_back
Definition: cfile.h:77
int no_miss
Definition: cfile.h:84
Zebra_mutex mutex
Definition: cfile.h:85
struct CFile_hash_bucket * bucket_lru_front
Definition: cfile.h:76
zint max_bucket_in_memory
Definition: cfile.h:80
zint * array
Definition: cfile.h:74
MFile block_mf
Definition: cfile.h:72
char * iobuf
Definition: cfile.h:81
zint bucket_in_memory
Definition: cfile.h:79
struct CFile_head head
Definition: cfile.h:70
MFile hash_mf
Definition: cfile.h:73
int dirty
Definition: cfile.h:78
char name[FILENAME_MAX+1]
Definition: mfile.h:79
long zint
Zebra integer.
Definition: util.h:66
#define ZINT_FORMAT
Definition: util.h:72
int zebra_mutex_unlock(Zebra_mutex *p)
Definition: zebra-lock.c:74
int zebra_mutex_init(Zebra_mutex *p)
Definition: zebra-lock.c:31
int zebra_mutex_lock(Zebra_mutex *p)
Definition: zebra-lock.c:59
int zebra_mutex_destroy(Zebra_mutex *p)
Definition: zebra-lock.c:43