Coverage Report

Created: 2025-10-28 07:06

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