Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libnczarr/zwalk.c
Line
Count
Source
1
/*********************************************************************
2
 *   Copyright 2018, UCAR/Unidata
3
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 *********************************************************************/
5
#include "zincludes.h"
6
7
#define WDEBUG
8
#undef DFALTOPTIMIZE
9
10
#define TRANSFERN
11
12
static int initialized = 0;
13
14
static unsigned int optimize = 0;
15
16
extern int NCZ_buildchunkkey(size_t R, const size64_t* chunkindices, char** keyp);
17
18
/* 0 => no debug */
19
static unsigned int wdebug = 1;
20
21
/* Forward */
22
static int NCZ_walk(NCZProjection** projv, NCZOdometer* chunkodom, NCZOdometer* slpodom, NCZOdometer* memodom, const struct Common* common, void* chunkdata);
23
static int rangecount(NCZChunkRange range);
24
static int readfromcache(void* source, size64_t* chunkindices, void** chunkdata);
25
static int iswholechunk(struct Common* common,NCZSlice*);
26
static int wholechunk_indices(struct Common* common, NCZSlice* slices, size64_t* chunkindices);
27
#ifdef TRANSFERN
28
static int transfern(const struct Common* common, unsigned char* slpptr, unsigned char* memptr, size_t avail, size_t slpstride, void* chunkdata);
29
#endif
30
31
#if 0
32
static const char*
33
astype(int typesize, void* ptr)
34
{
35
    switch(typesize) {
36
    case 4: {
37
  static char is[8]; 
38
  snprintf(is,sizeof(is),"%u",*((unsigned int*)ptr));
39
  return is;
40
        } break;
41
    default: break;
42
    }
43
    return "?";
44
}
45
#endif
46
47
/**************************************************/
48
int
49
ncz_chunking_init(void)
50
0
{
51
0
    const char* val = NULL;
52
#ifdef DFALTOPTIMIZE
53
    val = getenv("NCZ_NOOPTIMIZATION");
54
    optimize = (val == NULL ? 1 : 0);
55
#else
56
0
    optimize = 0;
57
0
#endif
58
0
    val = getenv("NCZ_WDEBUG");
59
0
    wdebug = (val == NULL ? 0 : atoi(val));
60
0
#ifdef WDEBUG
61
0
    if(wdebug > 0) fprintf(stderr,"wdebug=%u\n",wdebug);
62
0
#endif
63
0
    initialized = 1;
64
0
    return NC_NOERR;
65
0
}
66
67
/**************************************************/
68
69
/**
70
Goal: Given the slices being applied to the variable, create
71
and walk all possible combinations of projection vectors that
72
can be evaluated to provide the output data.
73
Note that we do not actually pass NCZSlice but rather
74
(start,count,stride) vectors.
75
76
@param var Controlling variable
77
@param usreading reading vs writing
78
@param start start vector
79
@param stop stop vector
80
@param stride stride vector
81
@param memory target or source of data
82
@param typecode nc_type of type being written
83
@param walkfcn fcn parameter to actually transfer data
84
*/
85
86
int
87
NCZ_transferslice(NC_VAR_INFO_T* var, int reading,
88
      size64_t* start, size64_t* count, size64_t* stride,
89
      void* memory, nc_type typecode)
90
0
{
91
0
    int r,stat = NC_NOERR;
92
0
    size64_t dimlens[NC_MAX_VAR_DIMS];
93
0
    unsigned char isunlimited[NC_MAX_VAR_DIMS];
94
0
    size64_t chunklens[NC_MAX_VAR_DIMS];
95
0
    size64_t memshape[NC_MAX_VAR_DIMS];
96
0
    NCZSlice slices[NC_MAX_VAR_DIMS];
97
0
    struct Common common;
98
0
    NCZ_FILE_INFO_T* zfile = NULL;
99
0
    NCZ_VAR_INFO_T* zvar = NULL;
100
0
    size_t typesize;
101
102
0
    if(!initialized) ncz_chunking_init();
103
104
0
    if((stat = NC4_inq_atomic_type(typecode, NULL, &typesize))) goto done;
105
106
0
    if(wdebug >= 1) {
107
0
        size64_t stopvec[NC_MAX_VAR_DIMS];
108
0
  for(r=0;r<var->ndims;r++) stopvec[r] = start[r]+(count[r]*stride[r]);
109
0
        fprintf(stderr,"var: name=%s",var->hdr.name);
110
0
        fprintf(stderr," start=%s",nczprint_vector(var->ndims,start));
111
0
        fprintf(stderr," count=%s",nczprint_vector(var->ndims,count));
112
0
        fprintf(stderr," stop=%s",nczprint_vector(var->ndims,stopvec));
113
0
        fprintf(stderr," stride=%s\n",nczprint_vector(var->ndims,stride));
114
0
    }
115
116
    /* Fill in common */
117
0
    memset(&common,0,sizeof(common));
118
0
    common.var = var;
119
0
    common.file = (var->container)->nc4_info;
120
0
    zfile = common.file->format_file_info;
121
0
    zvar = common.var->format_var_info;
122
123
0
    common.reading = reading;
124
0
    common.memory = memory;
125
0
    common.typesize = typesize;
126
0
    common.cache = zvar->cache;
127
128
    /* We need to take scalar into account */
129
0
    common.rank = var->ndims;
130
0
    common.scalar = zvar->scalar;
131
0
    common.swap = (zfile->native_endianness == var->endianness ? 0 : 1);
132
133
0
    common.chunkcount = 1;
134
0
    if(common.scalar) {
135
0
  dimlens[0] = 1;
136
0
  isunlimited[0] = 0;
137
0
  chunklens[0] = 1;
138
0
  slices[0].start = 0;
139
0
  slices[0].stride = 1;
140
0
  slices[0].stop = 0;
141
0
  slices[0].len = 1;
142
0
  common.chunkcount = 1;
143
0
  memshape[0] = 1;
144
0
    } else for(r=0;r<common.rank;r++) {
145
0
  dimlens[r] = var->dim[r]->len;
146
0
  isunlimited[r] = var->dim[r]->unlimited;
147
0
  chunklens[r] = var->chunksizes[r];
148
0
  slices[r].start = start[r];
149
0
  slices[r].stride = stride[r];
150
0
  slices[r].stop = start[r]+(count[r]*stride[r]);
151
0
  if(!isunlimited[r])
152
0
          slices[r].stop = minimum(slices[r].stop,dimlens[r]);
153
0
  slices[r].len = var->dim[r]->len;
154
0
  common.chunkcount *= chunklens[r];
155
0
  memshape[r] = count[r];
156
0
    }
157
158
0
    if(wdebug >= 1) {
159
0
        fprintf(stderr,"\trank=%d",common.rank);
160
0
        if(!common.scalar) {
161
0
        fprintf(stderr," dimlens=%s",nczprint_vector(common.rank,dimlens));
162
0
            fprintf(stderr," chunklens=%s",nczprint_vector(common.rank,chunklens));
163
0
            fprintf(stderr," memshape=%s",nczprint_vector(common.rank,memshape));
164
0
        }
165
0
  fprintf(stderr,"\n");
166
0
    }
167
168
    /* Transfer data */
169
0
    memcpy(common.dimlens,dimlens,sizeof(size64_t)*common.rank);
170
0
    memcpy(common.isunlimited,isunlimited,sizeof(unsigned char)*common.rank);
171
0
    memcpy(common.chunklens,chunklens,sizeof(size64_t)*common.rank);
172
0
    memcpy(common.memshape,memshape,sizeof(size64_t)*common.rank);
173
174
0
    common.reader.source = ((NCZ_VAR_INFO_T*)(var->format_var_info))->cache;
175
0
    common.reader.read = readfromcache;
176
177
0
    if(common.scalar) {
178
0
        if((stat = NCZ_transferscalar(&common))) goto done;
179
0
    }
180
0
    else {
181
0
        if((stat = NCZ_transfer(&common, slices))) goto done;
182
0
    }
183
0
done:
184
0
    NCZ_clearcommon(&common);
185
0
    return stat;
186
0
}
187
188
/*
189
Walk the possible projections.
190
Broken out so we can use it for unit testing
191
@param common common parameters
192
@param slices
193
*/
194
int
195
NCZ_transfer(struct Common* common, NCZSlice* slices)
196
0
{
197
0
    int stat = NC_NOERR;
198
0
    NCZOdometer* chunkodom =  NULL;
199
0
    NCZOdometer* slpodom = NULL;
200
0
    NCZOdometer* memodom = NULL;
201
0
    void* chunkdata = NULL;
202
0
    int wholechunk = 0;
203
204
    /*
205
     We will need three sets of odometers.
206
     1. Chunk odometer to walk the chunk ranges to get all possible
207
        combinations of chunkranges over all dimensions.
208
     2. For each chunk odometer set of indices, we need a projection
209
        odometer that walks the set of projection slices for a given
210
        set of chunk ranges over all dimensions. Note that this is where
211
  we detect unlimited extensions.
212
     3. A memory odometer that walks the memory data to specify
213
        the locations in memory for read/write
214
    */     
215
216
0
    if(wdebug >= 2)
217
0
  fprintf(stderr,"slices=%s\n",nczprint_slices(common->rank,slices));
218
219
0
    if((stat = NCZ_projectslices(common, slices, &chunkodom)))
220
0
  goto done;
221
222
0
    if(wdebug >= 4) {
223
0
  fprintf(stderr,"allprojections:\n%s",nczprint_allsliceprojections(common->rank,common->allprojections)); fflush(stderr);
224
0
    }
225
226
0
    wholechunk = iswholechunk(common,slices);
227
228
0
    if(wholechunk) {
229
        /* Implement a whole chunk read optimization; this is a rare occurrence
230
           where the the slices cover all of a single chunk.
231
        */
232
0
  size64_t chunkindices[NC_MAX_VAR_DIMS];
233
0
  unsigned char* memptr;
234
0
        unsigned char* slpptr;
235
236
  /* Which chunk are we getting? */
237
0
  if((stat=wholechunk_indices(common,slices,chunkindices))) goto done;
238
0
  if(wdebug >= 1)
239
0
      fprintf(stderr,"case: wholechunk: chunkindices: %s\n",nczprint_vector(common->rank,chunkindices));
240
  /* Read the chunk; handles fixed vs char* strings*/
241
0
        switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
242
0
        case NC_EEMPTY: /* cache created the chunk */
243
0
      break;
244
0
        case NC_NOERR: break;
245
0
        default: goto done;
246
0
        }
247
        /* Figure out memory address */
248
0
  memptr = ((unsigned char*)common->memory);
249
0
  slpptr = ((unsigned char*)chunkdata);
250
0
#ifdef TRANSFERN
251
0
        transfern(common,slpptr,memptr,common->chunkcount,1,chunkdata);
252
0
  if(!common->reading) {
253
0
      if((stat=NCZ_chunk_cache_modify(common->cache, chunkindices))) goto done;
254
0
  }
255
#else
256
  if(common->reading) {
257
      if((stat=NCZ_copy_data(common->file,common->var,slpptr,common->chunkcount,!ZCLEAR,memptr))) goto done;
258
  } else {
259
      if((stat=NCZ_copy_data(common->file,common->var,memptr,common->chunkcount,ZCLEAR,slpptr))) goto done;
260
      
261
  }
262
#endif
263
264
#ifdef UTTEST
265
        if(zutest && zutest->tests & UTEST_WHOLECHUNK)
266
      zutest->print(UTEST_WHOLECHUNK, common, chunkindices);
267
#endif
268
0
  goto done;
269
0
    }
270
271
    /* iterate over the odometer: all combination of chunk
272
       indices in the projections */
273
0
    for(;nczodom_more(chunkodom);) {
274
0
  int r;
275
0
  size64_t* chunkindices = NULL;
276
0
        NCZSlice slpslices[NC_MAX_VAR_DIMS];
277
0
        NCZSlice memslices[NC_MAX_VAR_DIMS];
278
0
        NCZProjection* proj[NC_MAX_VAR_DIMS];
279
0
  size64_t shape[NC_MAX_VAR_DIMS];
280
281
0
  chunkindices = nczodom_indices(chunkodom);
282
0
  if(wdebug >= 1)
283
0
      fprintf(stderr,"chunkindices: %s\n",nczprint_vector(common->rank,chunkindices));
284
285
0
  for(r=0;r<common->rank;r++) {
286
0
      NCZSliceProjections* slp = &common->allprojections[r];
287
0
      NCZProjection* projlist = slp->projections;
288
0
      size64_t indexr = chunkindices[r];
289
        /* use chunkindices[r] to find the corresponding projection slice */
290
      /* We must take into account that the chunkindex of projlist[r]
291
               may be greater than zero */
292
      /* note the 2 level indexing */
293
0
      indexr -= slp->range.start;
294
0
      NCZProjection* pr = &projlist[indexr];
295
0
      proj[r] = pr;
296
0
  }
297
298
0
  if(wdebug > 0) {
299
0
        fprintf(stderr,"Selected projections:\n");
300
0
      for(r=0;r<common->rank;r++) {
301
0
            fprintf(stderr,"\t[%d] %s\n",r,nczprint_projection(*proj[r]));
302
0
    shape[r] = proj[r]->iocount;
303
0
      }
304
0
      fprintf(stderr,"\tshape=%s\n",nczprint_vector(common->rank,shape));
305
0
  }
306
307
  /* See if any of the projections is a skip; if so, then move to the next chunk indices */
308
0
  for(r=0;r<common->rank;r++) {
309
0
      if(proj[r]->skip) goto next;
310
0
  }
311
312
0
  for(r=0;r<common->rank;r++) {
313
0
      slpslices[r] = proj[r]->chunkslice;
314
0
      memslices[r] = proj[r]->memslice;
315
0
  }
316
#ifdef UTTEST
317
  if(zutest && zutest->tests & UTEST_TRANSFER)
318
      zutest->print(UTEST_TRANSFER, common, chunkodom, slpslices, memslices);
319
#endif
320
321
        /* Read from cache */
322
0
        stat = common->reader.read(common->reader.source, chunkindices, &chunkdata);
323
0
  switch (stat) {
324
0
        case NC_EEMPTY: /* cache created the chunk */
325
0
      break;
326
0
        case NC_NOERR: break;
327
0
        default: goto done;
328
0
        }
329
330
0
  slpodom = nczodom_fromslices(common->rank,slpslices);
331
0
  memodom = nczodom_fromslices(common->rank,memslices);
332
333
0
  { /* walk with odometer */
334
0
      if(wdebug >= 1)
335
0
          fprintf(stderr,"case: odometer:\n");
336
        /* This is the key action: walk this set of slices and transfer data */
337
0
        if((stat = NCZ_walk(proj,chunkodom,slpodom,memodom,common,chunkdata))) goto done;
338
0
      if(!common->reading) {
339
0
          if((stat=NCZ_chunk_cache_modify(common->cache, chunkindices))) goto done;
340
0
      }
341
0
  }
342
0
next:
343
0
        nczodom_free(slpodom); slpodom = NULL;
344
0
        nczodom_free(memodom); memodom = NULL;
345
0
        nczodom_next(chunkodom);
346
0
    }
347
0
done:
348
0
    nczodom_free(slpodom);
349
0
    nczodom_free(memodom);
350
0
    nczodom_free(chunkodom);
351
0
    return stat;
352
0
}
353
354
#ifdef WDEBUG
355
static void
356
wdebug2(const struct Common* common, unsigned char* slpptr, unsigned char* memptr, size_t avail, size_t stride, void* chunkdata)
357
0
{
358
0
    unsigned char* slpbase = chunkdata;
359
0
    unsigned char* membase = common->memory;
360
0
    unsigned slpoff = (unsigned)(slpptr - slpbase);
361
0
    unsigned memoff = (unsigned)(memptr - membase);
362
0
    unsigned slpidx = slpoff / common->typesize;
363
0
    unsigned memidx = memoff / common->typesize;
364
0
    unsigned value;
365
366
0
    fprintf(stderr,"wdebug2: %s: [%u/%d] %u->%u",
367
0
      common->reading?"read":"write",
368
0
      (unsigned)avail,
369
0
          (unsigned)stride,
370
0
      (unsigned)(common->reading?slpidx:memidx),
371
0
      (unsigned)(common->reading?memidx:slpidx)
372
0
      );
373
0
    if(common->reading)
374
0
        value = ((unsigned*)slpptr)[0];
375
0
    else
376
0
        value = ((unsigned*)memptr)[0];
377
0
    fprintf(stderr,"; [%u]=%u",(unsigned)(common->reading?slpidx:memidx),value);
378
379
0
    fprintf(stderr,"\n");
380
0
}
381
#else
382
#define wdebug2(common,slpptr,memptr,avail,stride,chunkdata)
383
#endif
384
385
/*
386
Walk a set of slices and transfer data.
387
388
@param projv
389
@param chunkodom
390
@param slpodom
391
@param memodom
392
@param common
393
@param chunkdata
394
@return NC_NOERR
395
*/
396
static int
397
NCZ_walk(NCZProjection** projv, NCZOdometer* chunkodom, NCZOdometer* slpodom, NCZOdometer* memodom, const struct Common* common, void* chunkdata)
398
0
{
399
0
    int stat = NC_NOERR;
400
401
0
    for(;;) {
402
0
  size64_t slpoffset = 0;
403
0
  size64_t memoffset = 0;
404
0
  size64_t slpavail = 0;
405
0
  size64_t memavail = 0;
406
0
  size64_t laststride = 0;
407
0
  unsigned char* memptr0 = NULL;
408
0
  unsigned char* slpptr0 = NULL;
409
  
410
0
        if(!nczodom_more(slpodom)) break;
411
  
412
0
        if(wdebug >= 3) {
413
0
       fprintf(stderr,"xx.slp: odom: %s\n",nczprint_odom(slpodom));
414
0
       fprintf(stderr,"xx.mem: odom: %s\n",nczprint_odom(memodom));
415
0
        }
416
417
        /* Convert the indices to a linear offset WRT to chunk indices */
418
0
        slpoffset = nczodom_offset(slpodom);
419
0
        memoffset = nczodom_offset(memodom);
420
421
        /* transfer data between these addresses */
422
0
        memptr0 = ((unsigned char*)common->memory)+(memoffset * common->typesize);
423
0
        slpptr0 = ((unsigned char*)chunkdata)+(slpoffset * common->typesize);
424
425
0
        LOG((1,"%s: slpptr0=%p memptr0=%p slpoffset=%llu memoffset=%lld",__func__,slpptr0,memptr0,slpoffset,memoffset));
426
#ifdef UTTEST
427
  if(zutest && zutest->tests & UTEST_WALK)
428
       zutest->print(UTEST_WALK, common, chunkodom, slpodom, memodom);
429
#endif
430
  /* See if we can transfer multiple values at one shot */
431
0
  laststride = slpodom->stride[common->rank-1];
432
0
  if(laststride == 1) {
433
0
      slpavail = nczodom_avail(slpodom); /* How much can we read? */
434
0
      memavail = nczodom_avail(memodom);
435
0
      assert(memavail == slpavail);
436
0
      nczodom_skipavail(slpodom);
437
0
      nczodom_skipavail(memodom);
438
0
  } else {
439
0
      slpavail = 1;
440
0
        }
441
0
    if(slpavail > 0) {
442
0
if(wdebug > 0) {wdebug2(common,slpptr0,memptr0,slpavail,laststride,chunkdata);}
443
0
#ifdef TRANSFERN
444
0
            if((stat = transfern(common,slpptr0,memptr0,slpavail,nczodom_laststride(slpodom),chunkdata))) goto done;
445
#else
446
      if(common->reading) {
447
    if((stat=NCZ_copy_data(common->file,common->var,slpptr0,slpavail,!ZCLEAR,memptr0))) goto done;
448
      } else {
449
    if((stat=NCZ_copy_data(common->file,common->var,memptr0,slpavail,ZCLEAR,slpptr0))) goto done;
450
      }
451
#endif
452
0
  }
453
0
        nczodom_next(memodom);
454
0
        nczodom_next(slpodom);
455
0
    }
456
0
done:
457
0
    return stat;    
458
0
}
459
460
#if 0
461
#ifdef WDEBUG
462
static void
463
wdebug1(const struct Common* common, unsigned char* srcptr, unsigned char* dstptr, size_t count, size_t stride, void* chunkdata, const char* tag)
464
{
465
    unsigned char* dstbase = (common->reading?common->memory:chunkdata);
466
    unsigned char* srcbase = (common->reading?chunkdata:common->memory);
467
    unsigned dstoff = (unsigned)(dstptr - dstbase);
468
    unsigned srcoff = (unsigned)(srcptr - srcbase);
469
//    unsigned srcidx = srcoff / sizeof(unsigned);
470
471
    fprintf(stderr,"%s: %s: [%u/%d] %u->%u",
472
      tag,
473
      common->reading?"read":"write",
474
      (unsigned)count,
475
          (unsigned)stride,
476
      (unsigned)(srcoff/common->typesize),
477
      (unsigned)(dstoff/common->typesize)
478
      );
479
#if 0
480
    fprintf(stderr,"\t%s[%u]=%u\n",(common->reading?"chunkdata":"memdata"),
481
//      0,((unsigned*)srcptr)[0]
482
        srcidx,((unsigned*)srcbase)[srcidx]
483
  );
484
#endif
485
#if 0
486
    { size_t len = common->typesize*count;
487
    fprintf(stderr," | [%u] %u->%u\n",(unsigned)len,(unsigned)srcoff,(unsigned)dstoff);
488
    }
489
#endif
490
    fprintf(stderr,"\n");
491
}
492
#else
493
#define wdebug1(common,srcptr,dstptr,count,srcstride,dststride,chunkdata,tag)
494
#endif
495
#endif /*0*/
496
497
#ifdef TRANSFERN
498
static int
499
transfern(const struct Common* common, unsigned char* slpptr, unsigned char* memptr, size_t avail, size_t slpstride, void* chunkdata)
500
0
{
501
0
    int stat = NC_NOERR;
502
0
    nc_type xtype = common->var->type_info->hdr.id;
503
0
    size_t typesize = common->typesize;
504
0
    size_t len = typesize*avail;
505
0
    size_t m,s;
506
507
0
    if(common->reading) {
508
0
  if(slpstride == 1) {
509
0
      if((stat=NCZ_copy_data(common->file,common->var,slpptr,avail,common->reading,memptr))) goto done;
510
///            memcpy(memptr,slpptr,len); /* straight copy */
511
0
  } else {
512
0
      for(m=0,s=0;s<avail;s+=slpstride,m++) {
513
0
    size_t soffset = s*typesize;
514
0
    size_t moffset = m*typesize;
515
0
          if((stat=NCZ_copy_data(common->file,common->var,slpptr+soffset,1,common->reading,memptr+moffset))) goto done;
516
///     memcpy(memptr+moffset,slpptr+soffset,typesize);
517
0
      }
518
0
  }
519
0
        if(common->swap && xtype < NC_STRING)
520
0
            NCZ_swapatomicdata(len,memptr,common->typesize);
521
0
    } else { /*writing*/
522
0
unsigned char* srcbase = (common->reading?chunkdata:common->memory);
523
0
unsigned srcoff = (unsigned)(memptr - srcbase);
524
0
unsigned srcidx = srcoff / sizeof(unsigned); (void)srcidx;
525
0
  if(slpstride == 1) {
526
0
      if((stat=NCZ_copy_data(common->file,common->var,memptr,avail,common->reading,slpptr))) goto done;
527
///            memcpy(slpptr,memptr,len); /* straight copy */
528
0
  } else {
529
0
      for(m=0,s=0;s<avail;s+=slpstride,m++) {
530
0
    size_t soffset = s*typesize;
531
0
    size_t moffset = m*typesize;
532
0
          if((stat=NCZ_copy_data(common->file,common->var,memptr+moffset,1,common->reading,slpptr+soffset))) goto done;
533
///   memcpy(slpptr+soffset,memptr+moffset,typesize);
534
0
      }
535
0
  }
536
0
        if(common->swap && xtype < NC_STRING)
537
0
            NCZ_swapatomicdata(len,slpptr,common->typesize);
538
0
    }
539
0
done:
540
0
    return THROW(stat);
541
0
}
542
#endif /*TRANSFERN*/
543
544
#if 0
545
/* This function may not be necessary if code in zvar does it instead */
546
static int
547
NCZ_fillchunk(void* chunkdata, struct Common* common)
548
{
549
    int stat = NC_NOERR;    
550
551
    if(common->fillvalue == NULL) {
552
        memset(chunkdata,0,common->chunkcount*common->typesize);
553
  goto done;
554
    } 
555
556
    if(common->cache->fillchunk == NULL) {
557
        /* Get fill chunk*/
558
        if((stat = NCZ_create_fill_chunk(common->cache->chunksize, common->typesize, common->fillvalue, &common->cache->fillchunk)))
559
      goto done;
560
    }
561
    memcpy(chunkdata,common->cache->fillchunk,common->cache->chunksize);
562
done:
563
    return stat;
564
}
565
#endif
566
567
/* Break out this piece so we can use it for unit testing */
568
/**
569
@param slices
570
@param common
571
@param odomp
572
@return err code
573
*/
574
int
575
NCZ_projectslices(struct Common* common, 
576
                  NCZSlice* slices,
577
                  NCZOdometer** odomp)
578
0
{
579
0
    int stat = NC_NOERR;
580
0
    int r;
581
0
    NCZOdometer* odom = NULL;
582
0
    NCZSliceProjections* allprojections = NULL;
583
0
    NCZChunkRange ranges[NC_MAX_VAR_DIMS];
584
0
    size64_t start[NC_MAX_VAR_DIMS];
585
0
    size64_t stop[NC_MAX_VAR_DIMS];
586
0
    size64_t stride[NC_MAX_VAR_DIMS];
587
0
    size64_t len[NC_MAX_VAR_DIMS];
588
589
0
    if((allprojections = calloc((size_t)common->rank, sizeof(NCZSliceProjections))) == NULL)
590
0
        {stat = NC_ENOMEM; goto done;}
591
0
    memset(ranges,0,sizeof(ranges));
592
593
    /* Compute the chunk ranges for each slice in a given dim */
594
0
    if((stat = NCZ_compute_chunk_ranges(common,slices,ranges)))
595
0
        goto done;
596
597
    /* Compute the slice index vector */
598
0
    if((stat=NCZ_compute_all_slice_projections(common,slices,ranges,allprojections)))
599
0
        goto done;
600
601
    /* Verify */
602
0
    for(r=0;r<common->rank;r++) {
603
0
        assert(rangecount(ranges[r]) == allprojections[r].count);
604
0
    }
605
606
    /* Compute the shape vector */
607
0
    for(r=0;r<common->rank;r++) {
608
0
        int j;
609
0
        size64_t iocount = 0;
610
0
        NCZProjection* projections = allprojections[r].projections;
611
0
        for(j=0;j<allprojections[r].count;j++) {
612
0
            NCZProjection* proj = &projections[j];
613
0
            iocount += proj->iocount;
614
0
        }
615
0
        common->shape[r] = iocount;
616
0
    }
617
0
    common->allprojections = allprojections;
618
0
    allprojections = NULL;
619
620
    /* Create an odometer to walk all the range combinations */
621
0
    for(r=0;r<common->rank;r++) {
622
0
        start[r] = ranges[r].start; 
623
0
        stop[r] = ranges[r].stop;
624
0
        stride[r] = 1;
625
0
        len[r] = ceildiv(common->dimlens[r],common->chunklens[r]);
626
0
    }   
627
628
0
    if((odom = nczodom_new(common->rank,start,stop,stride,len)) == NULL)
629
0
        {stat = NC_ENOMEM; goto done;}
630
0
    if(odomp) *odomp = odom;
631
632
0
done:
633
    /* reclaim allprojections if !NULL */
634
0
    if(allprojections != NULL) {
635
0
        NCZ_clearsliceprojections(common->rank,allprojections);
636
0
  nullfree(allprojections);
637
0
    }
638
0
    return stat;
639
0
}
640
641
/***************************************************/
642
/* Utilities */
643
644
static int
645
rangecount(NCZChunkRange range)
646
0
{
647
0
    return (range.stop - range.start);
648
0
}
649
650
/* Goal: Given a set of per-dimension indices,
651
     compute the corresponding linear position.
652
*/
653
size64_t
654
NCZ_computelinearoffset(size_t R, const size64_t* indices, const size64_t* dimlens)
655
0
{
656
0
      size64_t offset;
657
0
      int i;
658
659
0
      offset = 0;
660
0
      for(i=0;i<R;i++) {
661
0
          offset *= dimlens[i];
662
0
          offset += indices[i];
663
0
      } 
664
0
      return offset;
665
0
}
666
667
#if 0
668
/* Goal: Given a linear position
669
     compute the corresponding set of R indices
670
*/
671
void
672
NCZ_offset2indices(size_t R, size64_t offset, const size64_t* dimlens, size64_t* indices)
673
{
674
      int i;
675
676
      for(i=0;i<R;i++) {
677
          indices[i] = offset % dimlens[i];
678
          offset = offset / dimlens[i];
679
      } 
680
}
681
#endif
682
683
/**************************************************/
684
/* Unit test entry points */
685
686
int
687
NCZ_chunkindexodom(int rank, const NCZChunkRange* ranges, size64_t* chunkcounts, NCZOdometer** odomp)
688
0
{
689
0
    int stat = NC_NOERR;
690
0
    int r;
691
0
    NCZOdometer* odom = NULL;
692
0
    size64_t start[NC_MAX_VAR_DIMS];
693
0
    size64_t stop[NC_MAX_VAR_DIMS];
694
0
    size64_t stride[NC_MAX_VAR_DIMS];
695
0
    size64_t len[NC_MAX_VAR_DIMS];
696
697
0
    for(r=0;r<rank;r++) {
698
0
        start[r] = ranges[r].start; 
699
0
        stop[r] = ranges[r].stop;
700
0
        stride[r] = 1;
701
0
        len[r] = chunkcounts[r];
702
0
    }   
703
704
0
    if((odom = nczodom_new(rank, start, stop, stride, len))==NULL)
705
0
        {stat = NC_ENOMEM; goto done;}
706
707
0
    if(odomp) {*odomp = odom; odom = NULL;}
708
709
0
done:
710
0
    nczodom_free(odom);
711
0
    return stat;
712
0
}
713
714
static int
715
readfromcache(void* source, size64_t* chunkindices, void** chunkdatap)
716
0
{
717
0
    return NCZ_read_cache_chunk((struct NCZChunkCache*)source, chunkindices, chunkdatap);
718
0
}
719
720
void
721
NCZ_clearcommon(struct Common* common)
722
0
{
723
0
    NCZ_clearsliceprojections(common->rank,common->allprojections);
724
0
    nullfree(common->allprojections);
725
0
}
726
727
/* Does the User want all of one and only chunk? */
728
static int
729
iswholechunk(struct Common* common, NCZSlice* slices)
730
0
{
731
0
    int i;
732
    
733
    /* Check that slices cover a whole chunk */
734
0
    for(i=0;i<common->rank;i++) {
735
0
  if(!(slices[i].stride == 1                            /* no point skipping              */
736
0
     && (slices[i].start % common->chunklens[i]) == 0 /* starting at beginning of chunk */
737
0
     && (slices[i].stop - slices[i].start)            /* stop-start = edge length       */
738
0
        == common->chunklens[i]                       /* edge length == chunk length    */
739
0
     )) 
740
0
      return 0; /* slices do not cover a whole chunk */
741
0
    }
742
0
    return 1;
743
0
}
744
745
static int
746
wholechunk_indices(struct Common* common, NCZSlice* slices, size64_t* chunkindices)
747
0
{
748
0
    int i;
749
0
    for(i=0;i<common->rank;i++)
750
0
  chunkindices[i] = (slices[i].start / common->chunklens[i]);
751
0
    return NC_NOERR;
752
0
}
753
754
/**************************************************/
755
/* Scalar variable support */
756
757
/*
758
@param common common parameters
759
*/
760
761
int
762
NCZ_transferscalar(struct Common* common)
763
0
{
764
0
    int stat = NC_NOERR;
765
0
    void* chunkdata = NULL;
766
0
    size64_t chunkindices[NC_MAX_VAR_DIMS];
767
0
    unsigned char* memptr, *slpptr;
768
769
    /* Read from single chunk from cache */
770
0
    chunkindices[0] = 0;
771
0
    switch ((stat = common->reader.read(common->reader.source, chunkindices, &chunkdata))) {
772
0
    case NC_EEMPTY: /* cache created the chunk */
773
0
  break;
774
0
    case NC_NOERR: break;
775
0
    default: goto done;
776
0
    }
777
778
    /* Figure out memory address */
779
0
    memptr = ((unsigned char*)common->memory);
780
0
    slpptr = ((unsigned char*)chunkdata);
781
0
#ifdef TRANSFERN
782
0
    if((stat = transfern(common,slpptr,memptr,1,1,chunkdata))) goto done;
783
#else
784
    if(common->reading) {
785
        if((stat=NCZ_copy_data(common->file,common->var,slpptr,common->chunkcount,!ZCLEAR,memptr))) goto done;
786
    } else {
787
        if((stat=NCZ_copy_data(common->file,common->var,memptr,common->chunkcount,ZCLEAR,slpptr))) goto done;
788
    }
789
#endif
790
791
0
done:
792
0
    return stat;
793
0
}
794
795
/* Debugging Interface: return the contents of a specified chunk */
796
EXTERNL int
797
NCZ_read_chunk(int ncid, int varid, size64_t* zindices, void* chunkdata)
798
0
{
799
0
    int stat = NC_NOERR;
800
0
    NC_FILE_INFO_T* h5 = NULL;
801
0
    NC_VAR_INFO_T* var = NULL;
802
0
    NCZ_VAR_INFO_T* zvar = NULL;
803
0
    struct NCZChunkCache* cache = NULL;
804
0
    void* cachedata = NULL;
805
806
0
    if ((stat = nc4_find_grp_h5_var(ncid, varid, &h5, NULL, &var)))
807
0
  return THROW(stat);
808
0
    zvar = (NCZ_VAR_INFO_T*)var->format_var_info;
809
0
    cache = zvar->cache;
810
811
0
    if((stat = NCZ_read_cache_chunk(cache,zindices,&cachedata))) goto done;
812
0
    if(chunkdata) {
813
0
  if((stat = NC_copy_data(h5->controller,var->type_info->hdr.id,cachedata,cache->chunkcount,chunkdata))) goto done;
814
0
    } 
815
    
816
0
done:
817
0
    return stat;
818
0
}