Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libdispatch/ncxcache.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
3
  See LICENSE.txt for license information.
4
*/
5
6
/** \file \internal
7
    Internal netcdf-4 functions.
8
9
    This file contains functions for manipulating NCxcache objects.
10
11
    Warning: This code depends critically on the assumption that
12
    |void*| == |uintptr_t|
13
14
*/
15
16
/* 0 => no debug */
17
#define DEBUG 0
18
#define CATCH
19
20
/* Define this for debug so that table sizes are small */
21
#define SMALLTABLE
22
23
#ifdef CATCH
24
0
#define THROW(x) throw(x)
25
0
static void breakpoint(void) {}
26
static int ignore[] = {0};
27
static int throw(int x)
28
0
{
29
0
    int* p;
30
0
    if(x != 0) {
31
0
  for(p=ignore;*p;p++) {if(x == *p) break;}
32
0
  if(*p == 0) breakpoint();
33
0
    }
34
0
    return x;
35
0
}
36
#else
37
#define THROW(x) (x)
38
#endif
39
40
#include "config.h"
41
#include <stdlib.h>
42
#include <stdio.h>
43
#include <string.h>
44
#ifdef HAVE_STDINT_H
45
#include <stdint.h>
46
#endif
47
#include <assert.h>
48
49
#include "nc4internal.h"
50
#include "ncexhash.h"
51
#include "ncxcache.h"
52
53
#ifdef SMALLTABLE
54
/* Keep the table sizes small initially */
55
#define DFALTTABLESIZE 4
56
0
#define DFALTLEAFLEN 4
57
#else
58
#define DFALTTABLESIZE 32
59
#define DFALTLEAFLEN 12
60
#endif
61
62
static void insertafter(NCxnode* current, NCxnode* node);
63
static void unlinknode(NCxnode* node);
64
65
#if DEBUG > 0
66
void verifylru(NCxcache* cache);
67
68
static void
69
xverify(NCxcache* cache)
70
{
71
    verifylru(cache);
72
}
73
74
void
75
verifylru(NCxcache* cache)
76
{
77
    NCxnode* p;
78
    for(p=cache->lru.next;p != &cache->lru;p=p->next) {
79
        if(p->next == NULL || p->prev == NULL) {
80
      xverify(cache);
81
  }
82
    }
83
}
84
#endif
85
86
/* Locate object by hashkey in an NCxcache */
87
int
88
ncxcachelookup(NCxcache* NCxcache, ncexhashkey_t hkey, void** op)
89
0
{
90
0
    int stat = NC_NOERR;
91
0
    uintptr_t inode = 0;
92
0
    NCxnode* node = NULL;
93
94
0
    if(NCxcache == NULL) return THROW(NC_EINVAL);
95
0
    assert(NCxcache->map != NULL);
96
0
    if((stat=ncexhashget(NCxcache->map,hkey,&inode)))
97
0
        {stat = THROW(NC_ENOOBJECT); goto done;} /* not present */
98
0
    node = (void*)inode;
99
0
    if(op) *op = node->content;
100
101
0
done:
102
0
    return stat;
103
0
}
104
105
/* Move object to the front of the LRU list */
106
int
107
ncxcachetouch(NCxcache* cache, ncexhashkey_t hkey)
108
0
{
109
0
    int stat = NC_NOERR;
110
0
    uintptr_t inode = 0;
111
0
    NCxnode* node = NULL;
112
113
0
    if(cache == NULL) return THROW(NC_EINVAL);
114
0
    if((stat=ncexhashget(cache->map,hkey,&inode)))
115
0
        {stat = THROW(NC_ENOOBJECT); goto done;} /* not present */
116
0
    node = (void*)inode;
117
    /* unlink */
118
0
    unlinknode(node);
119
    /* Relink into front of chain */
120
0
    insertafter(&cache->lru,node);
121
#if DEBUG > 0
122
verifylru(cache);
123
#endif
124
125
0
done:
126
0
    return stat;
127
0
}
128
129
/* Add object to the cache */
130
int
131
ncxcacheinsert(NCxcache* cache, const ncexhashkey_t hkey, void* o)
132
0
{
133
0
    int stat = NC_NOERR;
134
0
    uintptr_t inode = 0;
135
0
    NCxnode* node = NULL;
136
137
0
    if(cache == NULL) return THROW(NC_EINVAL);
138
    
139
#ifndef NCXUSER
140
    node = calloc(1,sizeof(NCxnode));
141
#else
142
0
    node = (NCxnode*)o;
143
0
#endif
144
0
    node->content = o; /* Cheat and make content point to the node part*/
145
0
    inode = (uintptr_t)node;
146
0
    stat = ncexhashput(cache->map,hkey,inode);
147
0
    if(stat)
148
0
  goto done;
149
    /* link into the LRU chain at front */
150
0
    insertafter(&cache->lru,node);
151
#if DEBUG > 0
152
verifylru(cache);
153
#endif
154
0
    node = NULL;
155
0
done:
156
#ifndef NCXUSER
157
    if(node) nullfree(node);
158
#endif
159
0
    return THROW(stat);
160
0
}
161
162
/* Remove object from the index;*/
163
int
164
ncxcacheremove(NCxcache* cache, ncexhashkey_t hkey, void** op)
165
0
{
166
0
    int stat = NC_NOERR;
167
0
    uintptr_t inode = 0;
168
0
    NCxnode* node = NULL;
169
170
0
    if(cache == NULL) return THROW(NC_EINVAL);
171
172
    /* Remove from the hash map */
173
0
    if((stat=ncexhashremove(cache->map,hkey,&inode)))
174
0
        {stat = NC_ENOOBJECT; goto done;} /* not present */
175
0
    node = (NCxnode*)inode;
176
    /* unlink */
177
0
    unlinknode(node);
178
#if DEBUG > 0
179
verifylru(cache);
180
#endif
181
0
    if(op) {
182
0
        *op = node->content;
183
0
    }
184
#ifndef NCXUSER
185
    nullfree(node);
186
#endif
187
188
0
done:
189
0
    return THROW(stat);
190
0
}
191
192
/* Free a cache */
193
void
194
ncxcachefree(NCxcache* cache)
195
0
{
196
0
    NCxnode* lru = NULL;
197
198
0
    if(cache == NULL) return;
199
0
    lru = &cache->lru;
200
201
#ifndef NCXUSER
202
    {
203
    NCxnode* p = NULL;
204
    NCxnode* next = NULL;
205
    /* walk the lru chain */
206
    next = NULL;
207
    for(p=lru->next;p != lru;) {
208
  next = p->next;
209
  nullfree(p);
210
  p = next;
211
    }
212
    }
213
#endif
214
215
0
    lru->next = (lru->prev = lru); /*reset*/
216
0
    ncexhashmapfree(cache->map);
217
0
    free(cache);
218
0
}
219
220
/* Create a new cache holding at least size objects */
221
int
222
ncxcachenew(size_t leaflen, NCxcache** cachep)
223
0
{
224
0
    int stat = NC_NOERR;
225
0
    NCxcache* cache = NULL;
226
227
0
    if(leaflen == 0) leaflen = DFALTLEAFLEN;
228
229
0
    cache = calloc(1,sizeof(NCxcache));
230
0
    if(cache == NULL)
231
0
        {stat = NC_ENOMEM; goto done;}
232
0
    cache->map = ncexhashnew(leaflen);
233
0
    if(cache->map == NULL)
234
0
        {stat = NC_ENOMEM; goto done;}
235
0
    cache->lru.next = &cache->lru;
236
0
    cache->lru.prev = &cache->lru;
237
0
    if(cachep) {*cachep = cache; cache = NULL;}
238
239
0
done:
240
0
    ncxcachefree(cache);
241
0
    return THROW(stat);
242
0
}
243
244
void
245
ncxcacheprint(NCxcache* cache)
246
0
{
247
0
    int i;
248
0
    NCxnode* p = NULL;
249
250
0
    fprintf(stderr,"NCxcache: lru=");
251
0
    fprintf(stderr,"{");
252
0
    for(i=0,p=cache->lru.next;p != &cache->lru;p=p->next,i++) {
253
0
  if(i>0) fprintf(stderr,",");
254
0
  fprintf(stderr,"%p:%p",p,p->content);
255
0
    }
256
0
    fprintf(stderr,"}\n");
257
0
    ncexhashprint(cache->map);
258
0
}
259
260
void*
261
ncxcachefirst(NCxcache* cache)
262
0
{
263
0
    if(cache == NULL) return NULL;
264
0
    if(ncexhashcount(cache->map) == 0)
265
0
        return NULL;
266
0
    return cache->lru.next->content;
267
0
}
268
269
void*
270
ncxcachelast(NCxcache* cache)
271
0
{
272
0
    if(cache == NULL) return NULL;
273
0
    if(ncexhashcount(cache->map) == 0)
274
0
        return NULL;
275
0
    return cache->lru.prev->content;
276
0
}
277
278
/* Insert node after current */
279
static void
280
insertafter(NCxnode* current, NCxnode* node)
281
0
{
282
0
    NCxnode* curnext = current->next;
283
0
    current->next = node;
284
0
    node->prev = current;
285
0
    node->next = curnext;
286
0
    curnext->prev = node;
287
0
}
288
289
/* Remove node from chain */
290
static void
291
unlinknode(NCxnode* node)
292
0
{
293
0
    NCxnode* next;
294
0
    NCxnode* prev;
295
0
    assert(node != NULL);
296
0
    next = node->next;
297
0
    prev = node->prev;
298
    /* repair the chain */
299
0
    next->prev = prev;
300
0
    prev->next = next;
301
0
    node->next = node->prev = NULL;
302
0
}
303
304
305
ncexhashkey_t
306
ncxcachekey(const void* key, size_t size)
307
0
{
308
0
    return ncexhashkey((unsigned char*)key,size);
309
0
}
310