1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF.  The full HDF copyright notice, including       *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /* $Id$ */
15 
16 /*LINTLIBRARY */
17 /* ------------------------------ HMCxxx -------------------------------
18    Routines to implement chunked elements via a Vdatas for
19    the chunk table and using a new data tag DFTAG_CHUNK to represent
20    each chunk object. As a result the *total* number of chunks
21    for all the chunked elements in an HDF file can only be as
22    large as sizeof(uint16) = 65,536(i.e. number of refs).
23 
24    This layer only has to deal with Chunks from a STDIO programming
25    model as this how special elements are viewed by other API's in the library.
26    The layers above deal with the more complex issues
27    of deciding what data to read/write next given the users request.
28    This layer basically chunks the element from a stream of bytes.
29    Note that this is different than if the layer was integrated
30    with say the SDS layer.
31 
32    NOTE: GeorgeV's standard Disclaimer <here>.
33          I was coerced to do it this way....:-)
34          If you break it .....you fix it...
35 
36    Description of file format headers for chunked element
37    ------------------------------------------------------
38    A chunked element is a special element.
39 
40    Special elements are
41    flagged with a set high-bit in their tag.  Thus, a tag t has
42    BASETAG == t & 0x7f and is a special tag if t & 0x80 != 0x00
43 
44    The first 16 bits of the meta-element that this tag/ref points to
45    tells us what type of special element this is.  If these 16 bits is
46    SPECIAL_CHUNKED, then it contains information about the chunked element.
47    After this 16 bits, 32 bit which is the length of each chunk, after
48    which is the information header:
49 
50    File Description of Chunked Element
51    ****************************************
52 
53    NOTE: I know some of the fields could be 1 byte instead of 4 bytes
54          but I decided to make them 4 to allow the fields to change
55          their behaviour in the future.....i.e some could hold tag/refs..
56 
57    DD for Chunked Element pointing to Chunked Description Record(12 byes )
58    =======================================================================
59    <-  2 bytes -> <- 2 bytes -> <- 4 bytes -> <- 4bytes ->
60    --------------------------------------------------------
61    |extended tag | reference # |  Offset     |  Length    |
62    --------------------------------------------------------
63                                     \______________/
64    __________________________________________|
65    V
66    CHUNKED DESCRIPTION RECORD(6 + 9 + 12 + 8 + 12 x ndims + 4 + fill_val_len +
67                               'specialness' bytes) > 52 bytes
68    ============================================================================
69    <-  2 bytes -> <-  4 bytes  -> (6 bytes)
70    --------------------------------
71    |sp_tag_desc  |sp_tag_head_len | ... cont'd
72    --------------------------------
73 
74    <-1 byte-> <- 4 bytes -> <-  4bytes  -> ( 9 bytes)
75    ------------------------------------------
76    | version |    flag     | elm_tot_length |... cont'd
77    ------------------------------------------
78 
79    <- 4 bytes  -> <- 4 bytes  -> <- 2 bytes -> <- 2 bytes -> (12 bytes)
80    ---------------------------------------------------------
81 ...| chunk_size  |  nt_size     | chk_tbl_tag | chk_tbl_ref | ...cont'd
82    ---------------------------------------------------------
83 
84    <- 2 bytes -> <- 2 bytes -> <- 4 bytes -> (8 bytes)
85    ----------------------------------------
86 ...| sp_tag     | sp_ref      |  ndims   |  ...cont'd
87    ----------------------------------------
88 
89    <- 4 bytes   -> <- 4 bytes -> <- 4 bytes -> (12 x ndims bytes)
90    --------------------------------------------
91 ...|    flag      | dim_length  | chunk_length |  ... x Number of dimensions
92    --------------------------------------------
93 
94    <-      4 bytes    -> <- variable bytes ->
95    ------------------------------------------
96 ...| fill_val_num_bytes | fill value......  |   ...(optional cont'd)
97    ------------------------------------------
98 
99           Optinal number of these depending on multiple 'specialness'
100           set in 'flag' field.
101 
102    <- 2 byte   -> <-      4 bytes  -> <- variable bytes -> (6 + variable bytes)
103    --------------------------------------------------------
104 ...| sp_tag_desc | sp_tag_header len | sp_tag_header......|...
105    --------------------------------------------------------
106 
107    Fields
108    ------
109    sp_tag_desc     - SPECIAL_CHUNKED(16 bit constant), identifies this as
110                      a chunked element description record
111    sp_tag_head_len - length of this special element header only.(4 bytes)
112                      Does not include length of header with additional
113                      'specialness' headers.
114                      NOTE: This is done to make this header layout similiar to the
115                            multiple 'specialiness' layout.
116    version        - version info (8 bit field)
117    flag           - bit field to set additional specialness  (32 bit field)
118                     only bottom 8bits used for now.
119    elem_tot_len   - Valid logical Length of the entire element(4 bytes)
120                     The logical physical length is this value multiplied
121                     by 'nt_size'.
122                     The actual physical length used for storage can be
123                     greater than the dataset size due to ghost areas in
124                     chunks. Partial chunks are not distinguished from
125                     regular chunks.
126    chunk_size     - logical size of data chunks(4 bytes)
127    nt_size        - Number type size i.e size of data type (4 bytes)
128    chk_tbl_tag    - Tag of chunk table i.e. Vdata (2 bytes)
129    chk_tbl_ref    - Reference number of the chunk table
130                     i.e. Vdata (2 bytes)
131    sp_tag         - For future use i.e. special table for 'ghost' chunks(2 bytes)
132    sp_ref         - For future use(2 bytes)
133    ndims          - number of dimensions for the chunked element.(4 bytes)
134    file_val_num_bytes - number of bytes in fill value (4 bytes)
135    fill value         - fill value (variable bytes)
136 
137    Fields for each dimension: (12 x ndims bytes)
138    --------------------------------------
139    flag           - (32 bit field)
140                     |High 8bits|Medium High 8bits|Medium Low 8bit|Low 8bits|
141                     o distrib_type (Low 8 bits, bits 0-7) -
142                       type of data distribution along this dimension
143                       0x00->None,
144                       0x01->Block
145                       Currently only block distribution is supported but
146                       this is not checked or verified for now.
147                     o other (Medium Low 8 bits, bits 7-15)
148                       0x00->Regular dimension,
149                       0x01->UNLIMITED dimension
150    dim_length     - current length of this dimension. (4 bytes)
151    chunk_length   - length of the chunk along this dimension (4 bytes)
152 
153    Fields for each additional 'specialness' (Optional)
154    -------------------------------------------
155    sp_tag_desc    - SPECIAL_xxx(16 bit constant), identifies this as
156                     a 'xxx' element description record .(16 bit field)
157    sp_tag_header_len - length of special element header(4 bytes)
158    sp_tag_header     - special header.(variable bytes)
159 
160 
161    Chunk Table(variable bytes per record in Vdata due to size of origin)
162    ====================================================================
163    <-  variable bytes -> <- 2 bytes -> <- 2 bytes ->
164    -------------------------------------------------
165    |      origin        |  chunk_tag  | chunk_ref_1 |
166    -------------------------------------------------
167            -                 -             -             N is number of
168            -                 -             -             chunk records
169            -                 -             -             in Vdata
170    -------------------------------------------------
171    |      origin        |  chunk_tag  | chunk_ref_N |
172    -------------------------------------------------
173                                  \______________/
174    __________________________________________|
175    V
176     <-   2 bytes  -> <- 2 bytes -> <- 4 bytes -> <- 4bytes ->
177     --------------------------------------------------------
178     | DFTAG_CHUNK   | chunk_ref_N |  Offset     |  Length    |
179     --------------------------------------------------------
180                                          \______________/
181         __________________________________________|
182         V
183         -----------------------
184         | Data_chunk          |
185         -----------------------
186                   Note: The "Length" here is specified by "chk_size" x "nt_size".
187 
188    Fields
189    ------
190    origin    - specifies the coordinates of the chunk in the overall
191                chunk array. (variable field, depends on number of
192                dimensions of chunked element).
193    chunk_tag - DFTAG_CHUNK for now(could be another chunked element to
194                allow recursive chunked elements(DFTAG_CHUNKED)) (16 bit field)
195    chunk_ref - Reference number of chunk itself   (16 bit field)
196 
197 EXPORTED ROUTINES
198 =================
199    User Public
200    -----------
201    HMCcreate       -- create a chunked element
202    HMCwriteChunk   -- write out the specified chunk to a chunked element
203    HMCreadChunk    -- read the specified chunk from a chunked element
204    HMCsetMaxcache  -- maximum number of chunks to cache
205    HMCPcloseAID    -- close file but keep AID active (For Hnextread())
206 
207    Library Private
208    ---------------
209    HMCPstread      -- open an access record for reading
210    HMCPstwrite     -- open an access record for writing
211    HMCPseek        -- set the seek posn
212    HMCPchunkread   -- read a single chunk out of a chunked element
213    HMCPread        -- read some data out of a chunked element
214    HMCPchunkwrite  -- write out a single chunk to a chunked element
215    HMCPwrite       -- write out some data to a chunked element
216    HMCPinquire     -- Hinquire for chunked element
217    HMCPendacess    -- close a chunked element AID
218    HMCPinfo        -- return info about a chunked element
219    HMCPgetnumrecs  -- get the number of records in a chunked element
220 
221    TBBT helper rotuines
222    -------------------
223    chkcompare      -- comprares 2 chunk records
224    chkfreekey      -- frees chunk key
225    chkdestroynode  -- destroys chunk record
226 
227 LOCAL ROUTINES
228 ==============
229    Chunking helper routines
230    ------------------------
231    create_dim_recs           -- create the appropriate arrays in memory
232    update_chunk_indices_seek -- translate seek pos to chunk and pos in chunk
233    compute_chunk_to_seek     -- translate chunk coordiantes to seek postion
234    update_chunk_indices      -- not used
235    compute_array_to_chunk    -- not used
236    calculate_num_to_chunk    -- not used
237    compute_chunk_to_array    -- translate chunk arrays to user array
238    compute_array_to_seek     -- translate user array to user seek position
239    calculate_seek_in_chunk   -- translate pos in chunk to seek pos in chunk
240    update_seek_pos_chunk     -- update chunk seek array with seek pos in chunk
241    calculate_chunk_num       -- translate chunk coordinates to a number
242    calculate_chunk_for_chunk -- calculate number of bytes to operate on chunk
243 
244    Common Routine
245    -------------
246    HMCIstaccess -- set up AID to access a chunked element
247 
248    AUTHOR
249    -------
250    -GeorgeV - 9/3/96
251 */
252 
253 /* For debugging */
254 /*
255 #define CHK_DEBUG_1
256 #define CHK_DEBUG_2
257 #define CHK_DEBUG_3
258 #define CHK_DEBUG_4
259 #define CHK_DEBUG_5
260 #define CHK_DEBUG_10
261 */
262 
263 
264 /* For Statistics from the chunk cache.
265    Note thate 'mache.c' must be compilied with -DSTATISTICS */
266 /*
267 #define STATISTICS
268 */
269 
270 #define  _HCHUNKS_MAIN_  /* Master chunk handling file */
271 #include "hdf.h"
272 #include "hfile.h"
273 #include "mcache.h" /* cache */
274 #include "hchunks.h"
275 
276 /* private functions */
277 PRIVATE int32
278 HMCIstaccess(accrec_t * access_rec,  /* IN: access record to fill in */
279              int16 acc_mode          /* IN: access mode */ );
280 
281 /* -------------------------------------------------------------------------
282 NAME
283     create_dim_recs -- create the appropriate arrays in memory
284 DESCRIPTION
285     Given number of dimensions create the following 3 arrays.
286     1. Dimension record array contains a record for each dimension.
287     2. Seek chunk indice array contains the seek postion relative to
288        the logical representation of the chunked array.
289     3. The seek position chunk array contains the seek postion
290        relative to the chunk itself.
291     4. The user array contains the users seek postion in the element
292 RETURNS
293     SUCCEED/FAIL
294 
295 AUTHOR
296    -GeorgeV - 9/3/96
297 ---------------------------------------------------------------------------*/
298 PRIVATE int32
create_dim_recs(DIM_REC ** dptr,int32 ** sbi,int32 ** spb,int32 ** sui,int32 ndims)299 create_dim_recs(DIM_REC **dptr, /* OUT: dimension record pointers */
300                 int32  **sbi,   /* OUT: seek chunk indices array */
301                 int32  **spb,   /* OUT: seek pos w/ chunk array */
302                 int32  **sui,   /* OUT: seek user indicies array */
303                 int32 ndims     /* IN: number of dimension of element */)
304 {
305     CONSTR(FUNC, "create_dim_recs");   /* for HERROR */
306     int32 i;
307     int32 ret_value = SUCCEED;
308 
309     /* allocate space for demension records pointers */
310     if ((*dptr = (DIM_REC *)HDmalloc(sizeof(DIM_REC) * (size_t)ndims)) == NULL)
311         HGOTO_ERROR(DFE_NOSPACE, FAIL);
312 
313     /* allocate space for seek chunk indices and chunk seek positions */
314     if ((*sbi = (int32 *)HDmalloc(sizeof(int32)*(size_t)ndims)) == NULL)
315         HGOTO_ERROR(DFE_NOSPACE, FAIL);
316 
317     if ((*spb = (int32 *)HDmalloc(sizeof(int32)*(size_t)ndims)) == NULL)
318         HGOTO_ERROR(DFE_NOSPACE, FAIL);
319 
320     /* allocate space for user seek indicies */
321     if ((*sui = (int32 *)HDmalloc(sizeof(int32)*(size_t)ndims)) == NULL)
322         HGOTO_ERROR(DFE_NOSPACE, FAIL);
323 
324     /* for each dimension */
325     for (i = 0; i < ndims; i++)
326       {
327           /* Initialize values for dimension record */
328           (*dptr)[i].flag = 0;
329           (*dptr)[i].dim_length = 0;
330           (*dptr)[i].chunk_length = 0;
331           (*dptr)[i].distrib_type = 0;
332           (*dptr)[i].unlimited = 0;
333           (*dptr)[i].last_chunk_length = 0;
334           (*dptr)[i].num_chunks = 0;
335 
336           (*sbi)[i] = 0;
337           (*spb)[i] = 0;
338           (*sui)[i] = 0;
339       } /* end for i */
340 
341   done:
342     if(ret_value == FAIL)
343       { /* Error condition cleanup */
344           if (*dptr != NULL)
345               HDfree(*dptr);
346           if (*sbi != NULL)
347               HDfree(*sbi);
348           if (*spb != NULL)
349               HDfree(*spb);
350           if (*sui != NULL)
351               HDfree(*sui);
352       } /* end if */
353 
354     /* Normal function cleanup */
355     return ret_value;
356 } /* end create_dim_recs() */
357 
358 /* -------------------------------------------------------------------------
359 NAME
360     update_chunk_indicies_seek -- translate seek pos to chunk and pos in chunk
361 DESCRIPTION
362     Give seek location within an element, calculate which chunk in
363     chunk array and position within chunk.
364 RETURNS
365     Nothing
366 AUTHOR
367    -GeorgeV - 9/3/96
368 ---------------------------------------------------------------------------*/
369 PRIVATE void
update_chunk_indicies_seek(int32 sloc,int32 ndims,int32 nt_size,int32 * sbi,int32 * spb,DIM_REC * ddims)370 update_chunk_indicies_seek(int32 sloc,    /* IN: physical Seek loc in element */
371                            int32 ndims,   /* IN: number of dimensions of elem */
372                            int32 nt_size, /* IN: number type size */
373                            int32 *sbi,    /* IN: seek chunk indicies array */
374                            int32 *spb,    /* IN: seek pos w/ chunk array */
375                            DIM_REC *ddims /* IN: dim record ptrs */)
376 {
377     int32 i;
378     int32 stmp;
379 
380     /* adjust physical seek->logical seek by using number type size */
381     stmp = sloc / nt_size;
382 #ifdef CHK_DEBUG_1
383           printf("ucis: sloc=%d, stmp=%d \n", sloc,stmp);
384 #endif
385     for(i = ndims - 1; i >= 0 ; i--)
386       { /* Calculate which chunk index in chunk representation */
387           sbi[i] = (int32)((stmp % ddims[i].dim_length)
388                            / ddims[i].chunk_length);
389           /* calculate starting postion in the chunk itself */
390           spb[i] = (int32)((stmp % ddims[i].dim_length)
391                            % ddims[i].chunk_length);
392 
393           stmp = stmp / ddims[i].dim_length;
394       } /* end for i */
395 #ifdef CHK_DEBUG_1
396     printf("ucis: chunk_array =(");
397     for(i = 0; i < ndims; i++)
398         printf("%d%s", sbi[i], i!= ndims-1 ? ",":NULL);
399     printf(")\n");
400 
401     printf("ucis: chunk_pos_array =(");
402     for(i = 0; i < ndims; i++)
403         printf("%d%s", spb[i], i!= ndims-1 ? ",":NULL);
404     printf(")\n");
405 #endif
406 } /* update_chunk_indicies_seek()*/
407 
408 #ifdef UNUSED
409 /* -------------------------------------------------------------------------
410 NAME
411     compute_chunk_to_seek -- translate chunk coordinates to chunk seek postion
412 DESCRIPTION
413     Calculate new chunk seek postion given seek chunk array and seek postion
414     within that chunk array.
415 RETURNS
416     Nothing
417 AUTHOR
418    -GeorgeV - 9/3/96
419 ---------------------------------------------------------------------------*/
420 PRIVATE void
compute_chunk_to_seek(int32 * chunk_seek,int32 ndims,int32 nt_size,int32 * sbi,int32 * spb,DIM_REC * ddims,int32 chunk_size)421 compute_chunk_to_seek(int32 *chunk_seek, /* OUT: new physical chunk seek pos in element*/
422                      int32 ndims,       /* IN: number of dims */
423                      int32 nt_size,     /* IN: number type size */
424                      int32 *sbi,        /* IN: seek chunk array */
425                      int32 *spb,        /* IN; seek pos w/ chunk array */
426                      DIM_REC *ddims,    /* IN: dim record ptrs */
427                      int32 chunk_size   /* IN: physical size of chunk */)
428 {
429     int32 j;
430     int32 new_seek;
431     int32 l_chunk_size = 0;
432 
433     /* Adjust physical chunk_size -> logical chunk size by size of number type */
434     l_chunk_size = chunk_size / nt_size;
435 
436     /* Calculate Seek Location in element
437      * First calculste seek-chunk position in element
438      * i.e seek position according to chunk first */
439     *chunk_seek = sbi[ndims -1];
440     for(j = ndims - 1; j; j--)
441       {
442           *chunk_seek = (*chunk_seek * ddims[j-1].num_chunks)
443               + sbi[j-1];
444       }
445 
446     /* must get chunk_size from somewhere else
447      * to give us position in file relative to chunk.
448      * Next comes adjustment of seek for postion inside chunk*/
449     *chunk_seek *= l_chunk_size;
450 #ifdef CHK_DEBUG_1
451     printf("ccs:  chunk_seek = %d(chunk# %d)\n", *chunk_seek,
452            *chunk_seek/l_chunk_size);
453 #endif
454     /* Calculate seek position in chunk */
455     new_seek = spb[ndims - 1];
456     for(j = ndims - 1; j; j--)
457       {
458           new_seek = (new_seek * ddims[j - 1].chunk_length)
459               + spb[j - 1];
460       }
461 
462     /* add seek position in chunk to seek-chunk offset */
463     new_seek += *chunk_seek;
464 #ifdef CHK_DEBUG_1
465     printf("ccs:   calculated seek position in file is %d\n", new_seek);
466 #endif
467 
468     /* multiply by number type size to get new physical seek positon */
469     *chunk_seek = new_seek * nt_size;
470 
471 } /* compute_chunk_to_seek() */
472 #endif /* UNUSED */
473 
474 #if 0 /* NOT USED */
475 
476 /* -------------------------------------------------------------------------
477 NAME
478     update_chunk_indices
479 DESCRIPTION
480     Given chunk size and current chunk in chunk array and postion within
481     that chunk, update to new chunk in chunk array and postion within
482     the new chunk.
483 RETURNS
484     Nothing
485 AUTHOR
486    -GeorgeV - 9/3/96
487 ---------------------------------------------------------------------------*/
488 PRIVATE void
489 update_chunk_indices(int32 chunk_size, /* IN: physical size of chunk read/written*/
490                      int32 ndims,      /* IN: number of dimensions */
491                      int32 nt_size,    /* IN: number type size */
492                      int32 *sbi,       /* IN: seek chunk indicies array */
493                      int32 *spb,       /* IN: seek pos w/ chunk array */
494                      DIM_REC *ddims    /* IN: dim record ptrs */)
495 {
496     int32 change = 1;
497     int32 index = 0;
498     int32 l_chunk_size = 0;
499 #ifdef CHK_DEBUG_1
500     int32 i;
501 #endif
502 
503     /* Adjust physical chunk_size -> logical chunk size by size of number type */
504     l_chunk_size = chunk_size / nt_size;
505 #ifdef CHK_DEBUG_1
506     printf("uci: l_chunk_size=%d \n", l_chunk_size);
507 #endif
508     while(change && index < ndims)
509       { /* add chunk written to current chunk dimension */
510           spb[index] += l_chunk_size;
511           change = 0;
512           if(spb[index] == ddims[index].chunk_length)
513             { /* we've move to next chunk since we filled the previous one */
514 #ifdef CHK_DEBUG_1
515                 fprintf(stderr,"uci: going to next chunk along spb[%d] to access\n",
516                         index);
517 #endif
518                 spb[index] = 0; /* position at beginning of chunk */
519                 if(++(sbi[index]) == ddims[index].num_chunks)
520                   { /* we've written to all the chunks in this demension,
521                        so reset for this dimension */
522 #ifdef CHK_DEBUG_1
523                     fprintf(stderr,"uci: accessed all chunks along sbi[%d] so reset \n",
524                             index);
525 #endif
526                       sbi[index] = 0;
527                       change = 1;
528                   }
529                 index++; /* go to next dimension */
530                 l_chunk_size = 1;
531             }
532       } /* end while "change" */
533 
534 #ifdef CHK_DEBUG_1
535     printf("uci : sbi =(");
536     for(i = 0; i < ndims; i++)
537         printf("%d%s", sbi[i], i!= ndims-1 ? ",":NULL);
538     printf(")\n");
539 
540     printf("uci : spb =(");
541     for(i = 0; i < ndims; i++)
542         printf("%d%s", spb[i], i!= ndims-1 ? ",":NULL);
543     printf(")\n");
544 #endif
545 } /* update_chunk_indices() */
546 
547 /* -------------------------------------------------------------------------
548 NAME
549     compute_array_to_chunk
550 DESCRIPTION
551     Calculate chunk array indicies and position within chunk
552     given user array indicies i.e. translates array postion in user
553     array to position in overall chunk array and within the chunk.
554 RETURNS
555     Nothing
556 AUTHOR
557    -GeorgeV - 9/3/96
558 ---------------------------------------------------------------------------*/
559 PRIVATE void
560 compute_array_to_chunk(int32 *chunk_indicies, /* OUT: chunk indicies */
561                        int32 *chunk_array_ind,/* OUT: chunk array indices */
562                        int32 *array_indicies, /* IN: array indicies */
563                        int32 ndims,           /* IN: number of dims */
564                        DIM_REC *ddims         /* IN: dim record ptrs */ )
565 {
566     int32 j;
567 
568     for(j = 0; j < ndims; j++)
569       {   /* set postion in overall chunk array */
570           chunk_indicies[j] = array_indicies[j] / ddims[j].chunk_length;
571           /* set postion within the chunk itself */
572           chunk_array_ind[j] = array_indicies[j] % ddims[j].chunk_length;
573       }
574 } /* compute_array_to_chunk() */
575 
576 
577 /* -------------------------------------------------------------------------
578 NAME
579     calculate_num_to_chunk
580 DESCRIPTION
581     Calculate seek chunk array given chunk number
582 
583     Not implemented
584 RETURNS
585     Nothing
586 AUTHOR
587    -GeorgeV - 9/3/96
588 ---------------------------------------------------------------------------*/
589 PRIVATE void
590 calculate_num_to_chunk(int32 chunk_num, /* IN: chunk number within element */
591                        int32 ndims,     /* IN: number of dims */
592                        int32 *sbi,      /* IN/OUT: seek chunk array */
593                        DIM_REC *ddims   /* IN: dim record ptrs */ )
594 {
595     int32 j;
596     int nchunk_num = chunk_num;
597 
598 
599 } /* calculate_num_chunk() */
600 
601 #endif /* NOT USED */
602 
603 /* -------------------------------------------------------------------------
604 NAME
605     compute_chunk_to_array -- translate chunk arrays to user array
606 DESCRIPTION
607     Calculate user array indicies given overall array chunk indicies
608     and position within chunk.
609 RETURNS
610     Nothing
611 AUTHOR
612    -GeorgeV - 9/3/96
613 ---------------------------------------------------------------------------*/
614 PRIVATE void
compute_chunk_to_array(int32 * chunk_indicies,int32 * chunk_array_ind,int32 * array_indicies,int32 ndims,DIM_REC * ddims)615 compute_chunk_to_array(int32 *chunk_indicies, /* IN: chunk indicies */
616                        int32 *chunk_array_ind,/* IN: chunk array indices */
617                        int32 *array_indicies, /* OUT: array indicies */
618                        int32 ndims,           /* IN: number of dims */
619                        DIM_REC *ddims         /* IN: dim record ptrs */ )
620 {
621     int32 j;
622 
623     for(j = 0; j < ndims; j++)
624       {   /* set postion in using overall chunk array */
625           array_indicies[j] = chunk_indicies[j] * ddims[j].chunk_length;
626 
627           /* set postion  using the chunk itself
628              need to adjust for last chunk along each dimension */
629           if (chunk_indicies[j] == (ddims[j].num_chunks -1))
630             { /* last chunk along this dimension */
631               array_indicies[j] += (chunk_array_ind[j] > ddims[j].last_chunk_length)?
632                   ddims[j].last_chunk_length : chunk_array_ind[j];
633             }
634           else /* not last chunk along a dimension */
635               array_indicies[j] +=  chunk_array_ind[j];
636       }
637 
638 #ifdef CHK_DEBUG_1
639           printf("ccta: array_indicies:(");
640           for (j = 0; j < ndims; j++)
641               printf("%d%s", array_indicies[j], j!= ndims-1 ? ",":NULL);
642           printf(")\n");
643 #endif
644 } /* compute_chunk_to_array() */
645 
646 /* -------------------------------------------------------------------------
647 NAME
648     compute_array_to_seek -- translate user array to user seek position
649 DESCRIPTION
650     Computer user seek postion within element given user array.
651 RETURNS
652     Nothing
653 AUTHOR
654    -GeorgeV - 9/3/96
655 ---------------------------------------------------------------------------*/
656 PRIVATE void
compute_array_to_seek(int32 * user_seek,int32 * array_indicies,int32 nt_size,int32 ndims,DIM_REC * ddims)657 compute_array_to_seek(int32 *user_seek,      /* OUT: user seek */
658                       int32 *array_indicies, /* IN: user array indicies */
659                       int32 nt_size,         /* IN: number type size */
660                       int32 ndims,           /* IN: number of dims */
661                       DIM_REC *ddims         /* IN: dim record ptrs */ )
662 {
663     int32 j;
664     int32 cnum;
665 
666     /* Calculate seek position within user array */
667     *user_seek = array_indicies[ndims - 1];
668     if (ndims > 1)
669       {
670           cnum = 1;
671           for(j = ndims - 2; j >= 0 ; j--)
672             {
673                 cnum *= ddims[j + 1].dim_length;
674                 *user_seek += (array_indicies[j] * cnum );
675             }
676       }
677 
678     /* multiply by number type size to get new physical user seek positon */
679     *user_seek = *user_seek * nt_size;
680 
681 } /* compute_array_to_seek() */
682 
683 /* -------------------------------------------------------------------------
684 NAME
685     calculate_seek_in_chunk -- translate pos in chunk to seek pos in chunk
686 DESCRIPTION
687     Calculate seek postion within chunk
688 RETURNS
689     Nothing
690 AUTHOR
691    -GeorgeV - 9/3/96
692 ---------------------------------------------------------------------------*/
693 PRIVATE void
calculate_seek_in_chunk(int32 * chunk_seek,int32 ndims,int32 nt_size,int32 * spb,DIM_REC * ddims)694 calculate_seek_in_chunk(int32 *chunk_seek,/* OUT: new physical seek pos in element*/
695                         int32 ndims,      /* IN: number of dims */
696                         int32 nt_size,    /* IN: number type size */
697                         int32 *spb,       /* IN; seek pos w/ chunk array */
698                         DIM_REC *ddims    /* IN: dim record ptrs */ )
699 {
700     int32 j;
701     int32 cnum;
702 
703     /* Calculate seek position within chunk */
704     *chunk_seek = spb[ndims - 1];
705     if (ndims > 1)
706       {
707           cnum = 1;
708           for(j = ndims - 2; j >= 0 ; j--)
709             {
710                 cnum *= ddims[j + 1].chunk_length;
711                 *chunk_seek += (spb[j] * cnum );
712             }
713       }
714 
715     /* multiply by number type size to get new physical seek positon */
716     *chunk_seek = *chunk_seek * nt_size;
717 
718 } /* calculate_seek_in_chunk() */
719 
720 /* -------------------------------------------------------------------------
721 NAME
722     update_seek_pos_chunk -- update chunk seek array with seek pos in chunk
723 DESCRIPTION
724     Update chunk seek array with seek pos in chunk.
725 RETURNS
726     Nothing
727 AUTHOR
728    -GeorgeV - 9/3/96
729 ---------------------------------------------------------------------------*/
730 PRIVATE void
update_seek_pos_chunk(int32 chunk_seek,int32 ndims,int32 nt_size,int32 * spb,DIM_REC * ddims)731 update_seek_pos_chunk(int32 chunk_seek, /* IN: physical seek pos in chunk */
732                       int32 ndims,      /* IN: number of dims */
733                       int32 nt_size,    /* IN: number type size */
734                       int32 *spb,       /* OUT: seek pos w/ chunk array */
735                       DIM_REC *ddims    /* IN: dim record ptrs */ )
736 {
737     int32 i;
738     int32 stmp;
739 
740     /* adjust physical seek->logical seek by using number type size */
741     stmp = chunk_seek / nt_size;
742 
743     for(i = ndims - 1; i >= 0 ; i--)
744       {
745           /* calculate starting postion in the chunk itself */
746           spb[i] = (int32)(stmp % ddims[i].chunk_length);
747           stmp = stmp / ddims[i].chunk_length;
748       } /* end for i */
749 
750 #ifdef CHK_DEBUG_1
751     printf("uspc: spb[] =(");
752     for(i = 0; i < ndims; i++)
753         printf("%d%s", spb[i], i!= ndims-1 ? ",":NULL);
754     printf(")\n");
755 #endif
756 } /* update_seek_pos_chunk() */
757 
758 
759 /* -------------------------------------------------------------------------
760 NAME
761     calculate_chunk_num - translate chunk coordinates to a number
762 DESCRIPTION
763     Calculate new chunk number given seek chunk array and seek postion
764     within that chunk array.
765 RETURNS
766     Nothing
767 AUTHOR
768    -GeorgeV - 9/3/96
769 ---------------------------------------------------------------------------*/
770 PRIVATE void
calculate_chunk_num(int32 * chunk_num,int32 ndims,int32 * sbi,DIM_REC * ddims)771 calculate_chunk_num(int32 *chunk_num, /* OUT: new chunk number within element */
772                     int32 ndims,      /* IN: number of dims */
773                     int32 *sbi,       /* IN: seek chunk array */
774                     DIM_REC *ddims    /* IN: dim record ptrs */ )
775 {
776     int32 j;
777     int32 cnum;
778 
779     /* Calculate chunk number from overall chunk array indicies */
780     *chunk_num = sbi[ndims - 1];
781     if (ndims > 1)
782       {
783           cnum = 1;
784           for(j = ndims - 2; j >= 0 ; j--)
785             {
786                 cnum *= ddims[j + 1].num_chunks;
787                 *chunk_num += (sbi[j] * cnum );
788             }
789       }
790 
791 } /* calculate_chunk_num() */
792 
793 /* -------------------------------------------------------------------------
794 NAME
795     calculate_chunk_for_chunk - calculate number of bytes to operate on chunk
796 DESCRIPTION
797   Given the length of bytes to operate on and the size of bytes
798   already operated on, calculate how big of chunk can be written
799   to the current chunk.
800 RETURNS
801     Nothing
802 AUTHOR
803    -GeorgeV - 9/3/96
804 ---------------------------------------------------------------------------*/
805 PRIVATE void
calculate_chunk_for_chunk(int32 * chunk_size,int32 ndims,int32 nt_size,int32 len,int32 bytes_finished,int32 * sbi,int32 * spb,DIM_REC * ddims)806 calculate_chunk_for_chunk(int32 *chunk_size,   /* OUT: chunk size for this chunk */
807                           int32 ndims,         /* IN: number of dims */
808                           int32 nt_size,       /* IN: number type size */
809                           int32 len,           /* IN: total length to operate on */
810                           int32 bytes_finished,/* IN: bytes already operted on*/
811                           int32 *sbi,          /* IN: seek chunk array */
812                           int32 *spb,          /* IN: seek pos w/ chunk array */
813                           DIM_REC *ddims       /* IN: dim record ptrs */)
814 {
815     /* Is this the last chunk along fastest changing dimension(i.e. subscript).
816        In future maybe need to handle variable case of any dimension being
817        the fastest. */
818     if (sbi[ndims - 1] == (ddims[ndims - 1].num_chunks - 1))
819       { /* last chunk */
820           /* Calculate size of chunk to write for the last chunk */
821           if ((ddims[ndims -1].last_chunk_length - spb[ndims - 1]) * nt_size
822               > (len - bytes_finished))
823               *chunk_size = len - bytes_finished; /* less than a chunk to write */
824           else /* last full chunk */
825               *chunk_size = (ddims[ndims - 1].last_chunk_length - spb[ndims -1]) * nt_size;
826 
827       }
828     else /* not the last chunk */
829       {
830           /* Calculate size of chunk to write in this chunk */
831           if ((ddims[ndims -1].chunk_length - spb[ndims - 1]) * nt_size
832               > (len - bytes_finished))
833               *chunk_size = len - bytes_finished; /* less than a chunk to write */
834           else /* full chunk */
835               *chunk_size = (ddims[ndims - 1].chunk_length - spb[ndims -1]) * nt_size;
836       }
837 } /* calculate_chunk_for_chunk() */
838 
839 /* -------------------------------------------------------------------------
840 NAME
841     chkcompare
842 DESCRIPTION
843    Compares two chunk B-tree keys for equality.  Similar to memcmp.
844 
845    *** Only called by B-tree routines, should _not_ be called externally ***
846 RETURNS
847 
848 AUTHOR
849    -GeorgeV - 9/3/96
850 ---------------------------------------------------------------------------*/
851 intn
chkcompare(void * k1,void * k2,intn cmparg)852 chkcompare(void * k1,   /* IN: first key */
853            void * k2,   /* IN: second key */
854            intn cmparg /* IN: not sure? */)
855 {
856     intn  ret_value;
857     /* shut compiler up */
858     cmparg = cmparg;
859 
860     /* valid for integer keys */
861     ret_value = ((intn) ((*(int32 *) k1) - (*(int32 *) k2)));
862 
863     return ret_value;
864 }   /* chkcompare */
865 
866 /********* Helper fcns for dealing with chunk table TBBT tree ***************/
867 
868 /* -------------------------------------------------------------------------
869 NAME
870     chkfreekey
871 DESCRIPTION
872     Free key - used by tbbt routines
873     *** Only called by B-tree routines, should _not_ be called externally ***
874 
875 RETURNS
876    Nothing
877 AUTHOR
878    -GeorgeV - 9/3/96
879 ---------------------------------------------------------------------------*/
880 void
chkfreekey(void * key)881 chkfreekey(void * key /*IN: chunk key */ )
882 {
883     if (key != NULL)
884         HDfree(key);
885 } /* chkfreekey() */
886 
887 /* -------------------------------------------------------------------------
888 NAME
889     chkdestroynode
890 DESCRIPTION
891    Frees chunk B-Tree nodes
892    *** Only called by B-tree routines, should _not_ be called externally ***
893 
894 RETURNS
895    Nothing
896 AUTHOR
897    -GeorgeV - 9/3/96
898 ---------------------------------------------------------------------------*/
899 void
chkdestroynode(void * n)900 chkdestroynode(void * n /* IN: chunk record */ )
901 {
902     CHUNK_REC *t=(CHUNK_REC *)n;
903 
904     if (t != NULL)
905       {
906           /* free orgin first */
907           if (t->origin != NULL)
908               HDfree(t->origin);
909 
910           /* free chunk record structure */
911           HDfree((void *) t);
912       }
913 }   /* chkdestroynode */
914 
915 /* ----------------------------- HMCIstaccess ------------------------------
916 NAME
917    HMCIstaccess -- set up AID to access a chunked elem
918 
919 DESCRIPTION
920    Calls to HMCIstread and HMCIstwrite resolve to this function.
921    Given an active AID fill in all of the special information.
922    If this information has already been read in for a different
923    element use that else we must go out to the HDF file and
924    pull in the information ourselves
925 
926    This routine also creates the chunk cache for the chunked element.
927    The cache is initialzed with the physical size of each chunk,
928    the number of chunks in the object i.e. object size/ chunk size,
929    and the maximum number of chunks to cache in memory. Chunks in
930    the cache are dealt with by their number i.e. translation of
931    'origin' of chunk to a unique number. The default maximum number
932    of chunks is the cache is set the number of chunks along the
933    last dimension.
934 
935    NOTE: The cache itself could be used to cache any object into a number
936    of fixed size chunks so long as the read/write(page-in/page-out) routines know
937    how to deal with getting the correct chunk based on a number. These
938    routines can be found in 'mcache.c'.
939 
940 RETURNS
941    The AID of the access record on success FAIL on error.
942 AUTHOR
943    -GeorgeV - 9/3/96
944 ----------------------------------------------------------------------------*/
945 PRIVATE int32
HMCIstaccess(accrec_t * access_rec,int16 acc_mode)946 HMCIstaccess(accrec_t *access_rec, /* IN: access record to fill in */
947              int16 acc_mode        /* IN: access mode */)
948 {
949     CONSTR(FUNC, "HMCIstaccess");    /* for HERROR */
950     filerec_t  *file_rec = NULL;     /* file record */
951     chunkinfo_t *info    = NULL;     /* information about data elt */
952     int32       dd_aid;              /* AID for writing the special info */
953     uint16      data_tag, data_ref;  /* Tag/ref of the data in the file */
954     uint8       local_ptbuf[6];      /* 6 bytes for special header length */
955 #if 0
956     uint8       *c_sp_header = NULL;   /* special element header(dynamic) */
957 #endif
958     uint8       c_sp_header[256]="" ;   /* special element header buffer.
959                                            dynamic allocation causes
960                                            a problem on the HPUX -GV */
961     int32       interlace;           /* type of interlace */
962     int32       vdata_size;          /* size of Vdata */
963     int32       num_recs;            /* number of Vdatas */
964     uint8       *v_data = NULL;      /* Vdata record */
965     CHUNK_REC   *chkptr = NULL;      /* Chunk record */
966     int32       *chk_key   = NULL;   /* chunk key */
967     int32       npages     = 1;      /* number of chunks */
968     int32       chunks_needed;       /* default chunk cache size  */
969     int32       access_aid = FAIL;   /* access id */
970     int32       ret_value = SUCCEED;
971     char        name[VSNAMELENMAX + 1];  /* Vdata name */
972     char        class[VSNAMELENMAX + 1]; /* Vdata class */
973     char        v_class[VSNAMELENMAX + 1] = ""; /* Vdata class for comparison */
974     intn        i,j,k;                     /* loop indicies */
975 
976     /* Check args */
977     if (access_rec == NULL)
978         HGOTO_ERROR(DFE_ARGS, FAIL);
979 
980     /* validate file record id */
981     file_rec = HAatom_object(access_rec->file_id);
982     if (BADFREC(file_rec) || !(file_rec->access & acc_mode))
983         HGOTO_ERROR(DFE_ARGS, FAIL);
984 
985     /* set up some data in access record */
986     access_rec->special = SPECIAL_CHUNKED;
987     access_rec->posn    = 0;
988     access_rec->access  = (uint32)(acc_mode|DFACC_READ);
989 
990     /*
991      * Lets free old special info first,if one exists,
992      * before copying a new one
993      *
994      * Hmm.....this is what other special elements do currently
995      * don't know if this is really necessary.....but leave in for now..
996      */
997     if (access_rec->special_info != NULL)
998       {   /* special information record */
999           chunkinfo_t *tmpinfo = (chunkinfo_t *) access_rec->special_info;
1000 
1001           if (--(tmpinfo->attached) == 0)
1002             {   /* the last one so now.. */
1003                 /* free old info from Chunk tables ..etc*/
1004 
1005                 /* Sync chunk cache */
1006                 mcache_sync(info->chk_cache);
1007 
1008                 /* close/free chunk cache */
1009                 mcache_close(info->chk_cache);
1010 
1011                 /* Use Vxxx interface to free Vdata info */
1012                 VSdetach(info->aid);
1013 
1014                 /* free chunk tree */
1015                 tbbtdfree(info->chk_tree, chkdestroynode, chkfreekey);
1016 
1017                 /* free up stuff in special info */
1018                 if (tmpinfo->ddims != NULL)
1019                     HDfree(tmpinfo->ddims);
1020                 if (tmpinfo->seek_chunk_indices != NULL)
1021                     HDfree(tmpinfo->seek_chunk_indices);
1022                 if (tmpinfo->seek_pos_chunk != NULL)
1023                     HDfree(tmpinfo->seek_pos_chunk);
1024                 if (tmpinfo->seek_user_indices != NULL)
1025                     HDfree(tmpinfo->seek_user_indices);
1026 
1027                 if (tmpinfo->fill_val != NULL)
1028                     HDfree(tmpinfo->fill_val);
1029 
1030                 if (tmpinfo->comp_sp_tag_header != NULL)
1031                     HDfree(tmpinfo->comp_sp_tag_header);
1032                 if (tmpinfo->cinfo != NULL)
1033                     HDfree(tmpinfo->cinfo);
1034                 if (tmpinfo->minfo != NULL)
1035                     HDfree(tmpinfo->minfo);
1036                 /* free info struct last */
1037                 HDfree(tmpinfo);
1038 
1039                 access_rec->special_info = NULL;
1040             }
1041       } /* end if special->info already */
1042 
1043     /* get the info for the dataset i.e. tag/ref*/
1044     /* get info about chunk table i.e. Vdata? */
1045     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,NULL,NULL)==FAIL)
1046         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1047 
1048     /* if the special information are already in some other acc elt,
1049      * point to it  and return */
1050     access_rec->special_info = HIgetspinfo(access_rec);
1051     if (access_rec->special_info)
1052       { /* special info exists */
1053           ((chunkinfo_t *) access_rec->special_info)->attached++;
1054           file_rec->attach++;
1055           info = (chunkinfo_t *) access_rec->special_info;
1056           /* set return value */
1057           access_aid = HAregister_atom(AIDGROUP,access_rec);
1058       }
1059     else /* need to allocate a new special info and get it */
1060       {
1061           /* allocate space for special chunk info */
1062           if ((info = (chunkinfo_t *)HDmalloc(sizeof(chunkinfo_t))) == NULL)
1063               HGOTO_ERROR(DFE_NOSPACE, FAIL);
1064 
1065           info->seek_chunk_indices = NULL;
1066           info->seek_pos_chunk     = NULL;
1067           info->seek_user_indices = NULL;
1068           info->ddims     = NULL;
1069           info->chk_tree  = NULL;
1070           info->chk_cache = NULL;
1071           info->fill_val  = NULL;
1072           info->minfo     = NULL;
1073           info->cinfo     = NULL;
1074           info->comp_sp_tag_header   = NULL;
1075           info->comp_sp_tag_head_len = 0;
1076           info->num_recs  = 0; /* zero records to start with */
1077 
1078           /* read the special info structure from the file */
1079           if((dd_aid=Hstartaccess(access_rec->file_id,data_tag,data_ref,DFACC_READ))==FAIL)
1080               HGOTO_ERROR(DFE_CANTACCESS, FAIL);
1081 
1082           if (Hseek(dd_aid, 2, DF_START) == FAIL)
1083               HGOTO_ERROR(DFE_SEEKERROR, FAIL);
1084 
1085           /* first read special tag header length which is 4 bytes */
1086           if (Hread(dd_aid, 4, local_ptbuf) == FAIL)
1087               HGOTO_ERROR(DFE_READERROR, FAIL);
1088 
1089           /* Decode it */
1090           {
1091               uint8      *p = local_ptbuf;
1092               INT32DECODE(p, info->sp_tag_header_len);   /* 4 bytes */
1093           }
1094 
1095           /* Sanity check, the 256 limit is arbitrary and can
1096              be removed later....*/
1097           if (info->sp_tag_header_len < 0 || info->sp_tag_header_len > 256)
1098               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1099 
1100 #if 0 /* dynamic alocation causes a problem on HPUX, removed for now -GV */
1101           /* Allocate buffer space for rest of special header */
1102           if (( c_sp_header = (uint8 *) HDcalloc(info->sp_tag_header_len,1))==NULL)
1103               HGOTO_ERROR(DFE_NOSPACE, FAIL);
1104 #endif
1105           /* first read special header in */
1106           if (Hread(dd_aid, info->sp_tag_header_len, c_sp_header) == FAIL)
1107               HGOTO_ERROR(DFE_READERROR, FAIL);
1108 
1109           /* decode first special element header  */
1110           {
1111               uint8      *p = c_sp_header;
1112 
1113               /* version info */
1114               HDmemcpy(&info->version,p,1);      /* 1 byte  */
1115               p = p + 1;
1116 
1117               /* Should check version here to see if we can handle
1118                  this version of special format header before we go on */
1119               if (info->version != _HDF_CHK_HDR_VER)
1120                   HGOTO_ERROR(DFE_INTERNAL, FAIL);
1121 
1122               INT32DECODE(p, info->flag);         /* 4 bytes */
1123               INT32DECODE(p, info->length);       /* 4 bytes */
1124               INT32DECODE(p, info->chunk_size);   /* 4 bytes */
1125               INT32DECODE(p, info->nt_size);      /* 4 bytes */
1126               UINT16DECODE(p, info->chktbl_tag);  /* 2 bytes */
1127               UINT16DECODE(p, info->chktbl_ref);  /* 2 bytes */
1128               UINT16DECODE(p, info->sp_tag);      /* 2 bytes */
1129               UINT16DECODE(p, info->sp_ref);      /* 2 bytes */
1130               INT32DECODE(p, info->ndims);        /* 4 bytes */
1131                                                   /* = 29 bytes */
1132               /* create dimension, seek_block and seek_pos arrays
1133                  given number of dims */
1134               if (create_dim_recs(&(info->ddims),&(info->seek_chunk_indices),
1135                                   &(info->seek_pos_chunk),
1136                                   &(info->seek_user_indices),info->ndims) == FAIL)
1137                   HGOTO_ERROR(DFE_INTERNAL, FAIL);
1138 
1139               /* decode dimension stuff */
1140               for (j = 0; j < info->ndims; j++)
1141                 {
1142                     int32 odd_size;
1143 
1144                     INT32DECODE(p,(info->ddims[j].flag));          /* 4 bytes */
1145                     INT32DECODE(p,(info->ddims[j].dim_length));    /* 4 bytes */
1146                     INT32DECODE(p,(info->ddims[j].chunk_length));  /* 4 bytes */
1147                                                                   /* = 12 bytes */
1148 
1149                     /* check 'flag' and decode settings */
1150                     info->ddims[j].distrib_type = (int32)(0xff & info->ddims[j].flag);
1151                     info->ddims[j].unlimited = (int32)
1152                                     (0xff & ((uint32)(info->ddims[j].flag >> 8)));
1153 
1154                     info->ddims[j].num_chunks = info->ddims[j].dim_length /
1155                         info->ddims[j].chunk_length;
1156                     /* check to see if need to increase # of chunks along this dim*/
1157                     if ((odd_size = (info->ddims[j].dim_length % info->ddims[j].chunk_length)))
1158 
1159                       {
1160                           info->ddims[j].num_chunks++; /* increase by one */
1161                           /* set last chunk length */
1162                           info->ddims[j].last_chunk_length = odd_size;
1163                       }
1164                     else
1165                         info->ddims[j].last_chunk_length = info->ddims[j].chunk_length; /*  */
1166 
1167                     npages = npages * info->ddims[j].num_chunks;
1168                 }   /* = 12 x ndims bytes */
1169 
1170               /* decode fill value length */
1171               INT32DECODE(p,(info->fill_val_len));   /* 4 bytes */
1172 
1173               /* allocate space for fill value */
1174               if ((info->fill_val = HDmalloc((size_t)info->fill_val_len ))==NULL)
1175                   HGOTO_ERROR(DFE_NOSPACE, FAIL);
1176 
1177               /* finally decode fill value */
1178               HDmemcpy(info->fill_val,p, info->fill_val_len); /* 1 byte */
1179 
1180           } /* end decode special header */
1181 
1182           /* if multiply special deal with now */
1183           switch(info->flag & 0xff) /* only using 8bits for now */
1184             {
1185             case SPECIAL_COMP:
1186             {
1187                 uint16     sp_tag;
1188 
1189                 /* first read specail tag header length which is 2+4 bytes */
1190                 if (Hread(dd_aid, 6, local_ptbuf) == FAIL)
1191                     HGOTO_ERROR(DFE_READERROR, FAIL);
1192 
1193                 /* Decode compression header length */
1194                 {
1195                     uint8      *p = NULL;
1196 
1197                     p = local_ptbuf;
1198                     UINT16DECODE(p, sp_tag);                     /* 2 bytes */
1199                     INT32DECODE(p, info->comp_sp_tag_head_len);   /* 4 bytes */
1200                 }
1201 
1202                 /* Sanity check */
1203                 if (info->sp_tag_header_len < 0 || sp_tag != SPECIAL_COMP)
1204                     HGOTO_ERROR(DFE_INTERNAL, FAIL);
1205 
1206                 /* Allocate buffer space for compression special header */
1207                 if (( info->comp_sp_tag_header = HDcalloc(info->comp_sp_tag_head_len,1))==NULL)
1208                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
1209 
1210                 /* read special header in */
1211                 if (Hread(dd_aid, info->comp_sp_tag_head_len, info->comp_sp_tag_header) == FAIL)
1212                     HGOTO_ERROR(DFE_READERROR, FAIL);
1213 
1214                 /* allocate compression special info  */
1215                 if (( info->cinfo = (comp_info *) HDmalloc(sizeof(comp_info)))==NULL)
1216                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
1217                 if (( info->minfo = (model_info *) HDmalloc(sizeof(model_info)))==NULL)
1218                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
1219 
1220                 /* Decode header */
1221                 if (HCPdecode_header((uint8 *)info->comp_sp_tag_header,
1222                                      (comp_model_t *)&info->model_type, info->minfo,
1223                                      (comp_coder_t *)&info->comp_type, info->cinfo) == FAIL)
1224                     HGOTO_ERROR(DFE_INTERNAL, FAIL);
1225             }
1226               break;
1227             default:
1228                 /* Do nothing */
1229                 break;
1230             } /* end switch on specialness */
1231 
1232           /* end access to special info stuff */
1233           if(Hendaccess(dd_aid)==FAIL)
1234               HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1235 
1236           /* set up the chunk tables of the information */
1237           /* intialize TBBT tree of CHUNK records*/
1238           info->chk_tree = tbbtdmake(chkcompare, sizeof(int32), TBBT_FAST_INT32_COMPARE);
1239 
1240           /* Use Vdata interface to read in chunk table and
1241              store per chunk-info in memory using TBBT trees  */
1242 
1243           /* Start access on Vdata */
1244           if(Vstart(access_rec->file_id) == FAIL)
1245               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1246 
1247           /* Attach to Vdata with write access if we are writing
1248              else read access */
1249           if (access_rec->access & DFACC_WRITE)
1250             {
1251                 if((info->aid = VSattach(access_rec->file_id, (int32)info->chktbl_ref, "w")) == FAIL)
1252                     HGOTO_ERROR(DFE_CANTATTACH, FAIL);
1253             }
1254           else /* attach with read access only */
1255             {
1256                 if((info->aid = VSattach(access_rec->file_id, (int32)info->chktbl_ref, "r")) == FAIL)
1257                     HGOTO_ERROR(DFE_CANTATTACH, FAIL);
1258             }
1259 
1260           /* get relevant info on Vdata */
1261           if ((VSinquire(info->aid, &num_recs, &interlace, NULL, &vdata_size, name)) == FAIL)
1262               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1263 
1264           /* Get class of Vdata */
1265           if ((VSgetclass(info->aid, class)) == FAIL)
1266               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1267 
1268           /* verify class and version */
1269           sprintf(v_class,"%s%d",_HDF_CHK_TBL_CLASS,_HDF_CHK_TBL_CLASS_VER);
1270           if (HDstrncmp(class,v_class,HDstrlen(v_class)) != 0 )
1271             {
1272 #ifdef CHK_DEBUG_2
1273                 fprintf(stderr," error, wrong class=%s, %d \n",class,HDstrlen(class));
1274                 fprintf(stderr,"            v_class=%s, %d \n",v_class,HDstrlen(v_class));
1275 #endif
1276               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1277             }
1278 
1279           /* Check to see if any chunks have been written out yet */
1280           if (num_recs > 0)
1281             { /* Yes */
1282                 /* Set the fields to read */
1283                 if(VSsetfields(info->aid,_HDF_CHK_FIELD_NAMES)==FAIL)
1284                     HGOTO_ERROR(DFE_BADFIELDS,FAIL);
1285 
1286                 /* Allocate space for a single Vdata record */
1287                 if ((v_data = HDmalloc((size_t)vdata_size)) == NULL)
1288                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
1289 
1290                 /* for each record read it in and put into TBBT tree
1291                    NOTE: Should change this to a single VSread() but then
1292                    would have to store all the v_data rec's somewhere
1293                    before inserting them into the TBBT tree...
1294                    ....for somone to do later if performance of VSread() is bad.
1295                    Technically a B+-Tree should have been used instead or
1296                    better yet the Vdata implementation should be re-written to use one.
1297                    Note that chunk tag DTAG_CHUNK is not verified here.
1298                    It is checked in HMCPchunkread() before the chunk is read. */
1299                 for (j = 0; j < num_recs; j++)
1300                   {
1301                       uint8 *pntr = NULL;
1302 
1303                       /* read single record */
1304                       if(VSread(info->aid,v_data,1,FULL_INTERLACE)==FAIL)
1305                           HGOTO_ERROR(DFE_VSREAD,FAIL);
1306 
1307                       pntr = v_data; /* set pointer to vdata record */
1308 
1309                       /* Allocate space for a chunk record */
1310                       if ((chkptr = (CHUNK_REC *) HDmalloc(sizeof(CHUNK_REC))) == NULL)
1311                           HGOTO_ERROR(DFE_NOSPACE, FAIL);
1312 
1313                       /* Allocate space for a origin in chunk record */
1314                       if ((chkptr->origin = (int32 *) HDmalloc((size_t)info->ndims*sizeof(int32))) == NULL)
1315                           HGOTO_ERROR(DFE_NOSPACE, FAIL);
1316 
1317                       /* allocate space for key */
1318                       if ((chk_key = (int32 *)HDmalloc(sizeof(int32))) == NULL)
1319                           HGOTO_ERROR(DFE_NOSPACE, FAIL);
1320 
1321                       /* Copy origin first */
1322                       for (k = 0; k < info->ndims; k++)
1323                         {
1324                             HDmemcpy(&chkptr->origin[k],pntr,sizeof(int32));
1325                             pntr += sizeof(int32);
1326 
1327                         }
1328 
1329 #ifdef CHK_DEBUG_2
1330                       printf(" chkptr->origin = (");
1331                       for (k = 0; k < info->ndims; k++)
1332                           printf("%d%s", chkptr->origin[k], k!= info->ndims-1 ? ",":NULL);
1333                       printf("), ");
1334 #endif
1335 
1336                       /* Copy tag next.
1337                          Note: Verification of tag as DTAG_CHUNK is done in
1338                          HMCPchunkread() before the chunk object is read.
1339                          In the future the tag/ref pair could point to
1340                          another chunk table...etc.
1341                          */
1342                       HDmemcpy(&chkptr->chk_tag,pntr,sizeof(uint16));
1343                       pntr += sizeof(uint16);
1344 #ifdef CHK_DEBUG_2
1345                       printf(" chktpr->chk_tag=%d, ",chkptr->chk_tag);
1346 #endif
1347                       /* Copy ref last */
1348                       HDmemcpy(&chkptr->chk_ref,pntr,sizeof(uint16));
1349 #ifdef CHK_DEBUG_2
1350                       printf(" chktpr->chk_ref=%d, ",chkptr->chk_ref);
1351                       printf("\n");
1352 #endif
1353                       /* now compute chunk number from origin */
1354                       calculate_chunk_num(chk_key, info->ndims, chkptr->origin,
1355                                           info->ddims);
1356 
1357                       chkptr->chunk_number = *chk_key;
1358 
1359                       /* set chunk number to record number */
1360                       chkptr->chk_vnum = info->num_recs++;
1361 
1362                       /* add to TBBT tree based on chunk number as the key */
1363                       tbbtdins(info->chk_tree, chkptr , chk_key);
1364                   } /* end for num_recs */
1365             } /* end if num_recs */
1366 
1367           /* set return value */
1368           access_aid = HAregister_atom(AIDGROUP,access_rec);
1369 
1370           /* create chunk cache with 'maxcache' set to the number of chunks
1371              along the last dimension i.e subscript changes the fastest*/
1372 	  chunks_needed = 1;
1373 	  for (i = 1; i < info->ndims; i++) {
1374 		chunks_needed *= info->ddims[i].num_chunks;
1375 	  }
1376           if ((info->chk_cache =
1377                mcache_open(&access_rec->file_id,                   /* cache key */
1378                            access_aid,                             /* object id */
1379                            (info->chunk_size*info->nt_size),       /* chunk size */
1380                            chunks_needed, /* maxcache */
1381                            npages,                                 /* num chunks */
1382                            0                                       /* flags */))
1383               == NULL)
1384               HE_REPORT_GOTO("failed to find initialize chunk cache", FAIL);
1385 
1386           /* set up chunk read/write routines
1387              These routines do the actual reading/writing of data
1388              from the file in whole chunks only. */
1389           mcache_filter(info->chk_cache, /* cache handle */
1390                         HMCPchunkread,   /* page-in routine */
1391                         HMCPchunkwrite,  /* page-out routine */
1392                         access_rec       /* object handle */);
1393 
1394           /* update chunk info data and file record info */
1395           info->attached = 1;
1396           file_rec->attach++;
1397           access_rec->special_info = (chunkinfo_t *) info;
1398       } /* end else need to get special info */
1399 
1400     /* access to data elments is done on a per chunk basis which
1401        can only be done in the read/write routines
1402        i.e. the cache pagin/pageout routines....*/
1403 
1404     ret_value = access_aid;
1405 
1406   done:
1407     if(ret_value == FAIL)
1408       { /* Error condition cleanup */
1409 
1410           /* free info struct */
1411           if (info != NULL)
1412             {
1413                 if (info->chk_cache != NULL)
1414                   {
1415                       /* Sync chunk cache */
1416                       mcache_sync(info->chk_cache);
1417 
1418                       /* close/free chunk cache */
1419                       mcache_close(info->chk_cache);
1420                   }
1421 
1422                 if (info->aid != FAIL)
1423                     VSdetach(info->aid);
1424 
1425                 /* free chunk tree */
1426                 if (info->chk_tree != NULL)
1427                     tbbtdfree(info->chk_tree, chkdestroynode, chkfreekey);
1428 
1429                 /* free up stuff in special info */
1430                 if (info->ddims != NULL)
1431                     HDfree(info->ddims);
1432                 if (info->seek_chunk_indices != NULL)
1433                     HDfree(info->seek_chunk_indices);
1434                 if (info->seek_pos_chunk != NULL)
1435                     HDfree(info->seek_pos_chunk);
1436                 if (info->seek_user_indices != NULL)
1437                     HDfree(info->seek_user_indices);
1438                 if (info->fill_val != NULL)
1439                     HDfree(info->fill_val);
1440                 if (info->comp_sp_tag_header != NULL)
1441                     HDfree(info->comp_sp_tag_header);
1442                 if (info->cinfo != NULL)
1443                     HDfree(info->cinfo);
1444                 if (info->minfo != NULL)
1445                     HDfree(info->minfo);
1446 
1447                 HDfree(info);
1448 
1449                 access_rec->special_info = NULL;
1450             }
1451 
1452       } /* end if */
1453 
1454     /* Normal function cleanup */
1455 #if 0 /* dynamic alocation causes a problem on HPUX, removed for now -GV */
1456     /* free specail element header */
1457     if (c_sp_header != NULL)
1458         HDfree(c_sp_header);
1459 #endif
1460     /* free allocated space for vdata record */
1461     if (v_data != NULL)
1462         HDfree(v_data);
1463 
1464     return ret_value;
1465 }   /* HMCIstaccess */
1466 
1467 /* ------------------------------------------------------------------------
1468 NAME
1469    HMCcreate -- create a chunked element
1470 
1471 DESCRIPTION
1472    This routine takes an HDF element and promotes it into a
1473    chunked element.  Basically, the element becomes a chunked element
1474    allowing easy appending where the chunk records are stored in
1475    a Vdata.  If the element already exists, this is an error currently
1476    otherwise a new element is created.
1477 
1478    All of the pieces of the chunked element are the same size from
1479    the stand point of the element. If compression is used then
1480    each chunk is compressed and the compression layer takes
1481    care of it as the chunk layer sees each chunks as a seperate
1482    HDF object(DFTAG_CHUNK). The proper compression special header
1483    needs to be passed to the compression layer.
1484 
1485    The Vdata(chunk table) is made appendable with linked-block
1486    table size of 128.
1487 
1488    This routine also creates the chunk cache for the chunked element.
1489    The cache is initialzed with the physical size of each chunk,
1490    the number of chunks in the object i.e. object size/ chunk size,
1491    and the maximum number of chunks to cache in memory. Chunks in
1492    the cache are dealt with by their number i.e. translation of
1493    'origin' of chunk to a unique number. The default maximum number
1494    of chunks is the cache is set the number of chunks along the
1495    last dimension.
1496 
1497    NOTE: The cache itself could be used to cache any object into a number
1498    of fixed size chunks so long as the read/write(page-in/page-out) routines know
1499    how to deal with getting the correct chunk based on a number.These
1500    routines can be found in 'mcache.c'.
1501 
1502 RETURNS
1503    The AID of newly created chunked element, FAIL on error.
1504 AUTHOR
1505    -GeorgeV - 9/3/96
1506  --------------------------------------------------------------------------- */
1507 int32
HMCcreate(int32 file_id,uint16 tag,uint16 ref,uint8 nlevels,int32 fill_val_len,void * fill_val,HCHUNK_DEF * chk_array)1508 HMCcreate(int32 file_id,       /* IN: file to put chunked element in */
1509           uint16 tag,          /* IN: tag of element */
1510           uint16 ref,          /* IN: ref of element */
1511           uint8 nlevels,       /* IN: number of levels of chunks */
1512           int32 fill_val_len,  /* IN: fill value length in bytes */
1513           void *fill_val,      /* IN: fill value */
1514           HCHUNK_DEF *chk_array /* IN: structure describing chunk distribution
1515                                   can be an array? but we only handle 1 level */ )
1516 {
1517     CONSTR(FUNC, "HMCcreate");     /* for HERROR */
1518     filerec_t  *file_rec   = NULL; /* file record */
1519     accrec_t   *access_rec = NULL; /* access record */
1520     int32       dd_aid     = FAIL; /* AID for writing the special info */
1521     chunkinfo_t *info      = NULL; /* information for the chunked elt */
1522     uint8       *c_sp_header = NULL; /* special element header */
1523     int32       npages     = 1;    /* i.e. number of chunks in element */
1524     int32       chunks_needed;     /* default size of chunk cache */
1525     int32       access_aid = FAIL; /* access id */
1526     uint16      chktbl_ref;        /* the ref of the link structure
1527                                       chunk table i.e. Vdata */
1528     uint16      special_tag;       /* special version of this tag */
1529     atom_t      data_id;           /* dd ID of existing regular element */
1530     int32       sp_tag_header_len = 0; /* length of special header */
1531     int32       data_len   = 1;        /* logical length of element */
1532     int32       ret_value  = SUCCEED;
1533     char        v_name[VSNAMELENMAX + 1] = "";/* name of vdata i.e. chunk table */
1534     char        v_class[VSNAMELENMAX + 1] = ""; /* Vdata class */
1535     intn        i;                 /* loop index */
1536 
1537     /* shut compiler up */
1538     nlevels=nlevels;
1539 
1540     /* clear error stack and validate file record id */
1541     HEclear();
1542     file_rec = HAatom_object(file_id);
1543 
1544     /* validate args */
1545     if (BADFREC(file_rec) || chk_array == NULL)
1546         HGOTO_ERROR(DFE_ARGS, FAIL);
1547 
1548     /* check file access for write */
1549     if (!(file_rec->access & DFACC_WRITE))
1550         HGOTO_ERROR(DFE_DENIED, FAIL);
1551 
1552     /* check if we are accidently passwed a special tag already */
1553     if(SPECIALTAG(tag)
1554        || (special_tag = MKSPECIALTAG(tag)) == DFTAG_NULL)
1555         HGOTO_ERROR(DFE_ARGS, FAIL);
1556 
1557     /* get empty slot in access records */
1558     access_rec = HIget_access_rec();
1559     if (access_rec == NULL)
1560         HGOTO_ERROR(DFE_TOOMANY, FAIL);
1561 
1562     /* search for identical dd */
1563     if ((data_id = HTPselect(file_rec,tag,ref))!=FAIL)
1564       {
1565           /*  this is where if a tag was already special i.e. compressed
1566               we would have to note it and promote it maybe? */
1567           /* Check if the element is already special */
1568           if (HTPis_special(data_id)==TRUE)
1569             {
1570                 HTPendaccess(data_id);
1571                 HGOTO_ERROR(DFE_CANTMOD, FAIL);
1572             }   /* end if */
1573 
1574       } /* end if */
1575 
1576     /* In theory we can have more than one level of chunks so
1577        we need to repeat the following steps. This would
1578        allow subchunking but currently haven't decided how
1579        the user would pass this info to routine to create the
1580        proper chunk tables...etc.
1581 
1582        Do we need to create special chunk table to handle the
1583        special chunks i.e. ghost chunks.-> Pass on this for now  */
1584 
1585 #if 0
1586     /* Okay we need to get a new ref for CHUNK table tag for first level */
1587     chktbl_ref = Htagnewref(file_id,DFTAG_CHUNKED);
1588 #endif
1589 
1590     /* allocate and fill in special chunk info struct for CHUNKs */
1591     if (( info = (chunkinfo_t *) HDmalloc(sizeof(chunkinfo_t)))==NULL)
1592         HGOTO_ERROR(DFE_NOSPACE, FAIL);
1593 
1594     info->attached     = 1;
1595     info->aid          = FAIL;
1596     info->version      = _HDF_CHK_HDR_VER ;     /* verson 1 for now */
1597     info->flag         = chk_array->chunk_flag; /* SPECIAL_COMP ? */
1598     info->cinfo        = NULL;
1599     info->minfo        = NULL;
1600     info->comp_sp_tag_head_len = 0;
1601     info->comp_sp_tag_header   = NULL;
1602     info->chunk_size   = chk_array->chunk_size; /* logical chunk size */
1603     info->nt_size      = chk_array->nt_size;    /* number type size */
1604     info->ndims        = chk_array->num_dims;   /* number of dimensions */
1605     info->sp_tag       = DFTAG_NULL;            /* not used currently */
1606     info->sp_ref       = 0;                     /* not used currently */
1607     info->seek_chunk_indices = NULL;
1608     info->seek_pos_chunk = NULL;
1609     info->seek_user_indices = NULL;
1610     info->ddims          = NULL;
1611     info->chk_tree       = NULL;
1612     info->chk_cache      = NULL;
1613     info->num_recs       = 0;                   /* zero Vdata records to start */
1614     info->fill_val_len   = fill_val_len;        /* length of fill value */
1615     /* allocate space for fill value */
1616     if (( info->fill_val = HDmalloc((uint32)fill_val_len))==NULL)
1617         HGOTO_ERROR(DFE_NOSPACE, FAIL);
1618     /* copy fill value over */
1619     HDmemcpy(info->fill_val, fill_val, info->fill_val_len); /* fill_val_len bytes */
1620 
1621     /* if compression set then fill in info i.e ENCODE for storage */
1622     switch(info->flag & 0xff) /* only using 8bits for now */
1623       {
1624       case SPECIAL_COMP:
1625           /* set compression info */
1626           /* allocate compression special info  */
1627           if (( info->cinfo = (comp_info *) HDmalloc(sizeof(comp_info)))==NULL)
1628               HGOTO_ERROR(DFE_NOSPACE, FAIL);
1629           if (( info->minfo = (model_info *) HDmalloc(sizeof(model_info)))==NULL)
1630               HGOTO_ERROR(DFE_NOSPACE, FAIL);
1631 
1632           /* find compression header length */
1633           info->comp_sp_tag_head_len = HCPquery_encode_header(
1634               (comp_model_t)chk_array->model_type, chk_array->minfo,
1635               (comp_coder_t)chk_array->comp_type, chk_array->cinfo);
1636 
1637           /* allocate space for compression header */
1638           if (( info->comp_sp_tag_header = HDmalloc((size_t)info->comp_sp_tag_head_len))==NULL)
1639               HGOTO_ERROR(DFE_NOSPACE, FAIL);
1640 
1641           /* Encode header for storage */
1642           if (HCPencode_header((uint8 *)info->comp_sp_tag_header,
1643                                (comp_model_t)chk_array->model_type, chk_array->minfo,
1644                                (comp_coder_t)chk_array->comp_type, chk_array->cinfo) == FAIL)
1645               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1646 
1647           /* Decode header back for memory */
1648           if (HCPdecode_header((uint8 *)info->comp_sp_tag_header,
1649                                (comp_model_t *)&info->model_type, info->minfo,
1650                                (comp_coder_t *)&info->comp_type, info->cinfo) == FAIL)
1651               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1652           break;
1653       default:
1654           /* Do nothing */
1655           break;
1656       } /* end switch on specialness */
1657 
1658     /* Use Vxxx interface to create new Vdata to hold Chunk table */
1659     /* create/intialize chunk table (Vdata ) */
1660 
1661     /* Start access on Vdata */
1662     if(Vstart(file_id) == FAIL)
1663         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1664 
1665     /* Create Vdata */
1666     if((info->aid = VSattach(file_id, -1, "w")) == FAIL)
1667         HGOTO_ERROR(DFE_CANTATTACH, FAIL);
1668 
1669     /* get ref of Vdata */
1670     chktbl_ref = (uint16)VSQueryref(info->aid);
1671 
1672     info->chktbl_ref      = chktbl_ref; /* ref of chunk table */
1673 
1674     /* get tag of Vdata */
1675     info->chktbl_tag = (uint16)VSQuerytag(info->aid);
1676 
1677 #ifdef CHK_DEBUG_2
1678     fprintf(stderr,"HMCcreate: info->chktbl_tag =%d, info->chktbl_ref=%d \n",
1679             info->chktbl_tag, info->chktbl_ref);
1680 #endif
1681     /* Define fields of chunk table i.e. Vdata */
1682 
1683     /* Define origin - order based on number of dims */
1684     if(VSfdefine(info->aid,_HDF_CHK_FIELD_1, DFNT_INT32,info->ndims) == FAIL)
1685         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1686 
1687     /* Define tag of chunk
1688        Note that the tag could be another Chunk table to
1689        represent another level. useful for quadtrees...etc. */
1690     if(VSfdefine(info->aid,_HDF_CHK_FIELD_2, DFNT_UINT16,1) == FAIL)
1691         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1692 
1693     /* Define ref of chunk
1694        Note that the ref could be that of another Chunk table to
1695        represent another level. useful for quadtrees...etc. */
1696     if(VSfdefine(info->aid,_HDF_CHK_FIELD_3, DFNT_UINT16,1) == FAIL)
1697         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1698 
1699     /* Set Vdata name based on tag and ref of element and of tag/ref of Vdata.
1700        ...sort of a back pointer...so sue me...*/
1701     sprintf(v_name,"%s%d_%d_%d_%d",_HDF_CHK_TBL_NAME,tag, ref,
1702             info->chktbl_tag, info->chktbl_ref);
1703     if(VSsetname(info->aid,v_name) == FAIL)
1704         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1705 
1706     /* Set Vdata class and version */
1707     sprintf(v_class,"%s%d",_HDF_CHK_TBL_CLASS,_HDF_CHK_TBL_CLASS_VER);
1708     if(VSsetclass(info->aid,v_class) == FAIL)
1709         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1710 
1711     /* Set the fields to write */
1712     if(VSsetfields(info->aid,_HDF_CHK_FIELD_NAMES)==FAIL)
1713         HGOTO_ERROR(DFE_BADFIELDS,FAIL);
1714 
1715     /* create dimension, seek_block and seek_pos arrays given number of dims */
1716     if (create_dim_recs(&(info->ddims),&(info->seek_chunk_indices),
1717                         &(info->seek_pos_chunk),
1718                         &(info->seek_user_indices),info->ndims) == FAIL)
1719         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1720 
1721     /* Copy info from input to dimension arrays */
1722     data_len = 1;
1723     for (i = 0; i < info->ndims; i++)
1724       {
1725           int32 odd_size;
1726 
1727           info->ddims[i].distrib_type = chk_array->pdims[i].distrib_type;
1728           if (chk_array->pdims[i].dim_length == 0) /* check unlimited dimension */
1729             { /* yes, UNLIMITED */
1730                 info->ddims[i].unlimited = 1; /* set flag */
1731                 /* set dimension length to be at least the chunk length
1732                    along this dimension */
1733                 info->ddims[i].dim_length = chk_array->pdims[i].chunk_length;
1734             }
1735           else /* not an unlimited dimension */
1736               info->ddims[i].dim_length = chk_array->pdims[i].dim_length;
1737 
1738           /* set dimension 'flag' */
1739           info->ddims[i].flag =
1740           (int32)(0xffff & ((info->ddims[i].unlimited << 8)
1741                              | (info->ddims[i].distrib_type)));
1742 
1743           info->ddims[i].chunk_length = chk_array->pdims[i].chunk_length;
1744           info->ddims[i].num_chunks = info->ddims[i].dim_length /
1745                                       info->ddims[i].chunk_length;
1746           /* check to see if need to increase # of chunks along this dim */
1747           if ((odd_size = (info->ddims[i].dim_length % info->ddims[i].chunk_length)))
1748             {
1749                 info->ddims[i].num_chunks++; /* increase by one */
1750                 /* set last chunk length */
1751                 info->ddims[i].last_chunk_length = odd_size;
1752             }
1753           else
1754               info->ddims[i].last_chunk_length = info->ddims[i].chunk_length; /*  */
1755 
1756 
1757           /* calculate number of chunks/pages in element */
1758           npages = npages * info->ddims[i].num_chunks;
1759 
1760           /* compute logical element length */
1761           data_len *= info->ddims[i].dim_length;
1762 
1763 #ifdef CHK_DEBUG_2
1764           printf("HMCcreate: dim[%d].dim_length=%d,",i,info->ddims[i].dim_length);
1765           printf("dim[%d].chunk_length=%d,",i,info->ddims[i].chunk_length);
1766           printf("dim[%d].num_chunks=%d \n",i,info->ddims[i].num_chunks);
1767 #endif
1768       }  /* end for ndims */
1769 #ifdef CHK_DEBUG_2
1770     printf("\n");
1771 #endif
1772 
1773     /* Make Vdata appendable with linked block table size of 'npages'
1774        if less than 128 and greater than 16.
1775        Not the best heuristic but for now it should be okay...*/
1776     if (npages > 16 && npages < 128)
1777       {
1778           if (VSappendable(info->aid, npages) == FAIL)
1779               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1780       }
1781     else if (npages < 16 )
1782       { /* 16 is default */
1783           if (VSappendable(info->aid, 16) == FAIL)
1784               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1785       }
1786     else /* use 128 for large chunk tables for now */
1787       {
1788           if (VSappendable(info->aid, 128) == FAIL)
1789               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1790       }
1791 
1792     /* Set logical length of element */
1793     info->length = data_len;              /* logical size of element */
1794 
1795     /* Calculate total length of this special element header
1796        including the fields for 'sp_tag_desc' and 'sp_tag_head_len'.
1797        See description of format header at top of file for more
1798        info on fields.
1799        Include also length for multiply specialness headers */
1800     switch(info->flag & 0xff) /* only using 8bits for now */
1801       {
1802       case SPECIAL_COMP:
1803           sp_tag_header_len = 6 + 9 + 12 + 8 +(12*info->ndims) + 4 + info->fill_val_len
1804                             + 6 + info->comp_sp_tag_head_len;
1805           break;
1806       default:
1807           sp_tag_header_len = 6 + 9 + 12 + 8 +(12*info->ndims) + 4 + info->fill_val_len;
1808           break;
1809       }
1810 
1811     /* Allocate buffer space for header */
1812     if (( c_sp_header = (uint8 *) HDcalloc(sp_tag_header_len,1))==NULL)
1813         HGOTO_ERROR(DFE_NOSPACE, FAIL);
1814 
1815     /* Calculate length of this special element header itself.
1816        Note the value of 'sp_tag_head_len' in the file is the
1817        total length of this special object header - 6 bytes.
1818        beacuse the length of the fields 'sp_tag_desc'(2 bytes) and
1819        'sp_tag_head_len' (4 bytes) which are not included
1820        If also multiply special need to subtract another 6 byts plus
1821        length for multiply specialness headers */
1822     switch(info->flag & 0xff) /* only using 8bits for now */
1823       {
1824       case SPECIAL_COMP:
1825           info->sp_tag_header_len = sp_tag_header_len - 6 - 6 - info->comp_sp_tag_head_len;
1826           break;
1827       default:
1828           info->sp_tag_header_len = sp_tag_header_len - 6;
1829           break;
1830       }
1831 
1832     /* encode info into chunked descripton record */
1833     {
1834         uint8      *p = c_sp_header;
1835         intn        j;
1836 
1837         UINT16ENCODE(p, SPECIAL_CHUNKED);        /* 2 bytes */
1838         INT32ENCODE(p, info->sp_tag_header_len); /* 4 bytes */
1839         HDmemcpy(p, &info->version,1);           /* 1 byte  */
1840         p = p + 1;
1841         INT32ENCODE(p, info->flag);         /* 4 bytes */
1842         INT32ENCODE(p, info->length);       /* 4 bytes */
1843         INT32ENCODE(p, info->chunk_size);   /* 4 bytes */
1844         INT32ENCODE(p, info->nt_size);      /* 4 bytes */
1845         UINT16ENCODE(p, info->chktbl_tag);  /* 2 bytes */
1846         UINT16ENCODE(p, info->chktbl_ref);  /* 2 bytes */
1847         UINT16ENCODE(p, info->sp_tag);      /* 2 bytes */
1848         UINT16ENCODE(p, info->sp_ref);      /* 2 bytes */
1849         INT32ENCODE(p, info->ndims);        /* 4 bytes */
1850                                             /* = 35 bytes*/
1851         for (j = 0; j < info->ndims; j++)
1852           {
1853               INT32ENCODE(p,(info->ddims[j].flag));         /* 4 bytes */
1854               INT32ENCODE(p,(info->ddims[j].dim_length));   /* 4 bytes */
1855               INT32ENCODE(p,(info->ddims[j].chunk_length)); /* 4 bytes */
1856           }                                               /* = 12 x ndims bytes */
1857 
1858         /* now for fill value */
1859         INT32ENCODE(p,(info->fill_val_len));            /* 4 bytes */
1860         HDmemcpy(p,info->fill_val,info->fill_val_len); /* fill_val_len bytes */
1861         p = p + fill_val_len;
1862 
1863         /* Future to encode multiply specialness stuff
1864            header lengths, header,..etc*/
1865         switch(info->flag & 0xff) /* only using 8bits for now */
1866           {
1867           case SPECIAL_COMP:
1868               UINT16ENCODE(p, SPECIAL_COMP);              /* 2 bytes */
1869               INT32ENCODE(p, info->comp_sp_tag_head_len); /* 4 bytes */
1870               /* copy special element header */
1871               HDmemcpy(p,info->comp_sp_tag_header,info->comp_sp_tag_head_len);
1872               p = p + info->comp_sp_tag_head_len;
1873               break;
1874           default:
1875               /* Do nothing */
1876               break;
1877           }
1878     }
1879 
1880     /* write the special info structure to fill */
1881     if((dd_aid = Hstartaccess(file_id,special_tag,ref,DFACC_ALL))==FAIL)
1882         HGOTO_ERROR(DFE_CANTACCESS, FAIL);
1883 
1884     /* write only the base 32 bytes ( 6 + 9 + 12 + 5)
1885        plus what is needed for each dimension which is (12 x ndims) bytes.
1886        plus for fill value 4 bytes + fill_val_len
1887        plus in future multiply special headers  = sp_tag_header_len */
1888     if (Hwrite(dd_aid, sp_tag_header_len, c_sp_header) == FAIL)
1889         HGOTO_ERROR(DFE_WRITEERROR, FAIL);
1890 
1891     /* end access to special info stuff in file */
1892     if(Hendaccess(dd_aid)==FAIL)
1893         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
1894 
1895     /* intialize TBBT tree of CHUNK records*/
1896     info->chk_tree = tbbtdmake(chkcompare, sizeof(int32), TBBT_FAST_INT32_COMPARE);
1897 
1898     /* Detach from the data DD ID */
1899     if(data_id != FAIL)
1900       {
1901           if(HTPendaccess(data_id)==FAIL)
1902               HGOTO_ERROR(DFE_INTERNAL, FAIL);
1903       }
1904 #ifdef CHK_DEBUG_2
1905     fprintf(stderr,"HMCcreate: special_tag =%d, ref=%d \n",
1906             special_tag, ref);
1907     fprintf(stderr,"HMCcreate: dd_aid =%d, data_id=%d \n",
1908             dd_aid, data_id);
1909 #endif
1910     /* update access record and file record */
1911     if((access_rec->ddid = HTPselect(file_rec,special_tag,ref))==FAIL)
1912         HGOTO_ERROR(DFE_INTERNAL, FAIL);
1913 
1914     access_rec->special      = SPECIAL_CHUNKED;
1915     access_rec->special_func = &chunked_funcs;
1916     access_rec->special_info = info;
1917     access_rec->posn         = 0;
1918     access_rec->access       = DFACC_RDWR;
1919     access_rec->file_id      = file_id;
1920     access_rec->appendable   = FALSE;     /* start data as non-appendable */
1921 
1922     file_rec->attach++;
1923 
1924 #ifdef CHK_DEBUG_2
1925     fprintf(stderr,"HMCcreate: access_rec->ddid =%d \n",
1926             access_rec->ddid);
1927 #endif
1928     /* register this valid access record for the chunked element */
1929     access_aid = HAregister_atom(AIDGROUP,access_rec);
1930 
1931     chunks_needed = 1;
1932     for (i = 1; i < info->ndims; i++) {
1933 	chunks_needed *= info->ddims[i].num_chunks;
1934     }
1935     /* create chunk cache */
1936     if ((info->chk_cache =
1937          mcache_open(&access_rec->file_id,                   /* cache key */
1938                      access_aid,                             /* object id */
1939                      (info->chunk_size*info->nt_size),       /* chunk size */
1940                      chunks_needed, /* maxcache */
1941                      npages,                                 /* num chunks */
1942                      0                                       /* flags */))
1943         == NULL)
1944         HE_REPORT_GOTO("failed to initialize chunk cache", FAIL);
1945 
1946     /*
1947       set up chunk read/write routines
1948       These routine are the actual routines that read/write
1949       whole chunks at a time.i.e. page-in/page-out routines
1950      */
1951     mcache_filter(info->chk_cache, /* cache handle */
1952                   HMCPchunkread,   /* page-in routine */
1953                   HMCPchunkwrite,  /* page-out routine */
1954                   access_rec       /* object handle */);
1955 
1956     ret_value = access_aid;
1957 
1958   done:
1959     if(ret_value == FAIL)
1960       { /* Error condition cleanup */
1961           /* free info struct */
1962           if (info != NULL)
1963             {
1964                 if (info->chk_cache != NULL)
1965                   {   /* Sync chunk cache */
1966                       mcache_sync(info->chk_cache);
1967 
1968                       /* close chunk cache */
1969                       mcache_close(info->chk_cache);
1970                   }
1971 
1972                 if (info->aid != FAIL)
1973                     VSdetach(info->aid); /* detach from chunk table */
1974 
1975                 /* free chunk tree */
1976                 if (info->chk_tree != NULL)
1977                     tbbtdfree(info->chk_tree, chkdestroynode, chkfreekey);
1978 
1979                 /* free up stuff in special info */
1980                 if (info->ddims != NULL)
1981                     HDfree(info->ddims);
1982                 if (info->seek_chunk_indices != NULL)
1983                     HDfree(info->seek_chunk_indices);
1984                 if (info->seek_pos_chunk != NULL)
1985                     HDfree(info->seek_pos_chunk);
1986                 if (info->fill_val != NULL)
1987                     HDfree(info->fill_val);
1988                 if (info->comp_sp_tag_header != NULL)
1989                     HDfree(info->comp_sp_tag_header);
1990                 if (info->cinfo != NULL)
1991                     HDfree(info->cinfo);
1992                 if (info->minfo != NULL)
1993                     HDfree(info->minfo);
1994                 HDfree(info); /* free spcial info last */
1995             }
1996 
1997           /* free access record */
1998           if(access_rec != NULL)
1999               HIrelease_accrec_node(access_rec);
2000       } /* end if */
2001 
2002     /* Normal function cleanup */
2003     /* free special element header */
2004     if (c_sp_header != NULL)
2005         HDfree(c_sp_header);
2006 
2007     return ret_value;
2008 } /* HMCcreate() */
2009 
2010 /*--------------------------------------------------------------------------
2011 NAME
2012      HMCgetcompress - get compression information for chunked element
2013 
2014 DESCRIPTION
2015      Checks if the given element is compressed then get the compression
2016      information using HCPdecode_header.
2017      This routine is used by HCgetcompress for the chunked element part.
2018 
2019 RETURNS
2020      Returns SUCCEED/FAIL
2021 
2022 REVISION LOG
2023      September 2001: Added to fix bug #307 - BMR
2024 
2025 -------------------------------------------------------------------------- */
2026 intn
HMCgetcompress(accrec_t * access_rec,comp_coder_t * comp_type,comp_info * c_info)2027 HMCgetcompress( accrec_t*    access_rec, /* IN: access record */
2028 		comp_coder_t* comp_type, /* OUT: compression type */
2029 		comp_info* c_info)       /* OUT: retrieved compression info */
2030 {
2031     CONSTR(FUNC, "HMCgetcompress");   /* for HERROR */
2032     chunkinfo_t *info = NULL;   /* chunked element information record */
2033     model_info  m_info;         /* modeling information - dummy */
2034     comp_model_t model_type;    /* modeling type - dummy */
2035     intn        ret_value = SUCCEED;
2036 
2037     /* Get the special info from the given record */
2038     info = (chunkinfo_t *) access_rec->special_info;
2039     if (info == NULL) HGOTO_ERROR(DFE_COMPINFO, FAIL);
2040 
2041     /* If this chunked element is compressed, retrieve its comp info */
2042     if (info->flag == SPECIAL_COMP)
2043     {
2044         /* Decode header from storage */
2045         ret_value = HCPdecode_header((uint8 *)info->comp_sp_tag_header,
2046                  &model_type, &m_info, /* dummy */
2047 		 comp_type, c_info);
2048     }
2049     /* It's not compressed */
2050     else
2051 	*comp_type = COMP_CODE_NONE;
2052 
2053   done:
2054     if(ret_value == FAIL)
2055       { /* Error condition cleanup */
2056 
2057       } /* end if */
2058 
2059     /* Normal function cleanup */
2060     return ret_value;
2061 } /* HMCgetcompress() */
2062 
2063 
2064 /*--------------------------------------------------------------------------
2065 NAME
2066      HMCgetcomptype - get compression information for chunked element
2067 
2068 DESCRIPTION
2069      Checks if the given element is compressed then get the compression
2070      information using HCPdecode_header.
2071      This routine is used by HCgetcompress for the chunked element part.
2072 
2073 RETURNS
2074      Returns SUCCEED/FAIL
2075 
2076 REVISION LOG
2077      September 2001: Added to fix bug #307 - BMR
2078 
2079 -------------------------------------------------------------------------- */
2080 intn
HMCgetcomptype(int32 dd_aid,comp_coder_t * comp_type)2081 HMCgetcomptype(int32 dd_aid, /* IN: access id of header info */
2082 	       comp_coder_t* comp_type) /* OUT: compression type */
2083 {
2084     CONSTR(FUNC, "HMCgetcomptype");   /* for HERROR */
2085     uint8 *bufp;		/* pointer to buffer */
2086     uint8  version;      /* Version of this Chunked element */
2087     int32  flag;         /* flag for multiply specialness ...*/
2088     uint16 c_type;    /* compression type */
2089     uint8 *c_sp_header = NULL; /* special element header */
2090     int32  sp_tag_header_len = 0; /* length of special header */
2091     int32  comp_sp_tag_head_len; /* Compression header length */
2092     VOID  *comp_sp_tag_header = NULL;  /* compression header */
2093     uint8  local_ptbuf[6];      /* 6 bytes for special header length */
2094     intn   ret_value = SUCCEED;
2095 
2096     /* first read special tag header length which is 4 bytes */
2097     if (Hread(dd_aid, 4, local_ptbuf) == FAIL)
2098 	HGOTO_ERROR(DFE_READERROR, FAIL);
2099 
2100     /* Decode it */
2101     bufp = local_ptbuf;
2102     INT32DECODE(bufp, sp_tag_header_len);   /* 4 bytes */
2103 
2104     /* Sanity check */
2105     if (sp_tag_header_len < 0)
2106 	HGOTO_ERROR(DFE_INTERNAL, FAIL);
2107 
2108     /* Allocate buffer space for rest of special header */
2109     if ((c_sp_header = (uint8 *) HDcalloc(sp_tag_header_len,1))==NULL)
2110 	HGOTO_ERROR(DFE_NOSPACE, FAIL);
2111 
2112     /* read special info header in */
2113     if (Hread(dd_aid, sp_tag_header_len, c_sp_header) == FAIL)
2114 	HGOTO_ERROR(DFE_READERROR, FAIL);
2115 
2116     /* decode special info header */
2117     bufp = c_sp_header;
2118 
2119     /* version info */
2120     HDmemcpy(&version, bufp, 1);      /* 1 byte  */
2121     bufp = bufp + 1;
2122 
2123     /* Should check version here to see if we can handle
2124     this version of special format header before we go on */
2125     if (version != _HDF_CHK_HDR_VER)
2126 	HGOTO_ERROR(DFE_INTERNAL, FAIL);
2127 
2128     /* flag indicating multiple specialness */
2129     INT32DECODE(bufp, flag);         /* 4 bytes */
2130 
2131     /* check for further specialness */
2132     switch(flag & 0xff)
2133       {
2134 	/* if the element is also compressed, read the compress special info
2135 	   header and decode to get the compression coder */
2136 	case SPECIAL_COMP:
2137 	{
2138 	    uint16     sp_tag;
2139 
2140 	    /* Read compression special tag and header length, 2+4 bytes */
2141 	    if (Hread(dd_aid, 6, local_ptbuf) == FAIL)
2142 		HGOTO_ERROR(DFE_READERROR, FAIL);
2143 
2144 	    /* Decode compression header length */
2145 		bufp = local_ptbuf;
2146 		UINT16DECODE(bufp, sp_tag);		/* 2 bytes */
2147 		INT32DECODE(bufp, comp_sp_tag_head_len);   /* 4 bytes */
2148 
2149 	    /* Sanity check */
2150 	    if (comp_sp_tag_head_len < 0 || sp_tag != SPECIAL_COMP)
2151 		HGOTO_ERROR(DFE_INTERNAL, FAIL);
2152 
2153 	    /* Allocate buffer space for compression special header */
2154 	    if ((comp_sp_tag_header = HDcalloc(comp_sp_tag_head_len,1))==NULL)
2155 		HGOTO_ERROR(DFE_NOSPACE, FAIL);
2156 
2157 	    /* Read compression special header in */
2158 	    if (Hread(dd_aid, comp_sp_tag_head_len, comp_sp_tag_header) == FAIL)
2159 		HGOTO_ERROR(DFE_READERROR, FAIL);
2160 
2161 	    /* Decode header to get compression type */
2162 	    bufp = comp_sp_tag_header;
2163 	    bufp = bufp + 2;	/* skip model type */
2164 	    UINT16DECODE(bufp, c_type);     /* get encoding type */
2165 	    *comp_type=(comp_coder_t)c_type;
2166 	    break;
2167 	}
2168 	/* It's not compressed */
2169 	default:
2170 	    *comp_type = COMP_CODE_NONE;
2171       } /* switch flag */
2172 
2173   done:
2174     if(ret_value == FAIL)
2175       { /* Error condition cleanup */
2176 
2177       } /* end if */
2178 
2179     /* Normal function cleanup */
2180     /* Free special element headers */
2181     if (c_sp_header != NULL)
2182         HDfree(c_sp_header);
2183     if (comp_sp_tag_header != NULL)
2184         HDfree(comp_sp_tag_header);
2185 
2186     return ret_value;
2187 } /* HMCgetcomptype() */
2188 
2189 
2190 /*--------------------------------------------------------------------------
2191 NAME
2192      HMCgetdatainfo - get data info (offset & length) of the chunked element
2193 
2194 DESCRIPTION
2195      - If the given chunk has data without any special storage, HMCgetdatainfo
2196        will return one pair of offset/length of the data.
2197      - If the chunk's data is compressed only, then HMCgetdatainfo will also
2198        return one pair of offset/length to the compressed data
2199      - If the chunk's data is compessed and is stored in linked-blocks, then
2200        HMCgetdatainfo will return a number of offset/length pairs for the
2201        the data's blocks.
2202 
2203 RETURNS
2204      Returns number of offset/length pairs retrieved or FAIL
2205 
2206 REVISION LOG
2207      March 2009: Added during hmap project. -BMR
2208      August 2010: Modified according to revised SDgetdatainfo -BMR
2209      Sept 2010: Mofified to handle chunk with comp and linked-blocks -BMR
2210      March 2011: Added an "else" to flag as an error if the chunk has additional
2211 	specialness other than compression, just in case if there is. -BMR
2212 
2213 -------------------------------------------------------------------------- */
2214 intn
HMCgetdatainfo(int32 file_id,uint16 tag,uint16 ref,int32 * chk_coord,uintn start_block,uintn info_count,int32 * offsetarray,int32 * lengtharray)2215 HMCgetdatainfo(int32 file_id,
2216 		uint16 tag,
2217 		uint16 ref,
2218 		int32* chk_coord,       /* IN: chunk number to be processed */
2219 		uintn start_block,	/* IN: data block to start at, 0 base */
2220 		uintn info_count,	/* IN: size of offset/length lists */
2221                 int32 *offsetarray,	/* OUT: array to hold offsets */
2222                 int32 *lengtharray)	/* OUT: array to hold lengths */
2223 {
2224     CONSTR(FUNC, "HMCgetdatainfo");	/* for HERROR */
2225     uint16	 comp_ref = 0;		/* ref# of compressed data */
2226     chunkinfo_t *chkinfo=NULL;		/* chunked element information */
2227     atom_t       ddid=FAIL;             /* description record access id */
2228     atom_t       cmpddid=FAIL;          /* description record access id */
2229     uint16	 new_tag=0, new_ref=0;
2230     int32	 new_off=0, new_len=0;
2231     intn	 count=0;		/* number of blocks */
2232     int32	 chk_num=0;
2233     CHUNK_REC   *chk_rec = NULL;	/* chunk record */
2234     TBBT_NODE   *entry   = NULL;	/* chunk node from TBBT */
2235     accrec_t *access_rec;
2236     filerec_t *file_rec;
2237     int32 new_aid=FAIL;
2238     int16        spec_code=0;
2239     uint8        lbuf[16];		/* temporary buffer */
2240     uint8       *p;			/* tmp buf ptr */
2241     intn	 ret_value = SUCCEED;
2242 
2243     /* Clear error stack */
2244     HEclear();
2245 
2246     /* Validate arguments */
2247     if (info_count == 0 && offsetarray != NULL && lengtharray != NULL)
2248         HGOTO_ERROR(DFE_ARGS, FAIL);
2249 
2250     file_rec = HAatom_object(file_id);
2251     if (BADFREC(file_rec))
2252 	HGOTO_ERROR(DFE_INTERNAL, FAIL);
2253 
2254     if ((new_aid = Hstartread(file_id, tag, ref))== FAIL)
2255 	HGOTO_ERROR(DFE_NOMATCH, FAIL);
2256 
2257     access_rec = HAatom_object(new_aid);
2258     if (access_rec == (accrec_t *) NULL)
2259 	HGOTO_ERROR(DFE_ARGS, FAIL);
2260 
2261     /* It should be chunked, but verify anyway, just in case */
2262     if (access_rec->special == SPECIAL_CHUNKED)
2263     {
2264 	if (access_rec->special_info != NULL)
2265 	    chkinfo = (chunkinfo_t *) (access_rec->special_info);
2266     }
2267     else
2268 	HGOTO_ERROR(DFE_INTERNAL, FAIL);
2269 
2270     /* Calculate chunk number from origin */
2271     calculate_chunk_num(&chk_num, chkinfo->ndims, chk_coord, chkinfo->ddims);
2272 
2273     /* Find chunk record in TBBT */
2274     if ((entry = (tbbtdfind(chkinfo->chk_tree, &chk_num, NULL))) == NULL)
2275     { /* chunk had not been written, no chunk record */
2276 	if (offsetarray != NULL && lengtharray != NULL)
2277 	{
2278 	    offsetarray[0] = 0;
2279 	    lengtharray[0] = 0;
2280 	}
2281 	count = 0;
2282     }
2283     else
2284     { /* chunk record exists */
2285         /* Get chunk record from node */
2286         chk_rec = (CHUNK_REC *) entry->data;
2287 
2288         /* Check to see if it has been written to */
2289         if (chk_rec->chk_tag != DFTAG_NULL && BASETAG(chk_rec->chk_tag) == DFTAG_CHUNK)
2290         { /* valid chunk in file */
2291 	    /* Check for further specialness */
2292  	    if (Hfind(file_id,chk_rec->chk_tag,chk_rec->chk_ref,&new_tag,&new_ref,
2293                    &new_off,&new_len,DF_FORWARD)==FAIL)
2294 	        HE_REPORT_GOTO("Hfind failed ", FAIL);
2295 
2296 	    if ((ddid = HTPselect(file_rec, new_tag, new_ref)) == FAIL)
2297 	        HE_REPORT_GOTO("HTPselect failed ", FAIL);
2298 
2299 	    if (HTPis_special(ddid)!=TRUE)
2300 	    { /* this chunk is not special */
2301 	        if (offsetarray != NULL && lengtharray != NULL)
2302 	        {
2303 		    offsetarray[0] = Hoffset(file_id, chk_rec->chk_tag, chk_rec->chk_ref);
2304 		    lengtharray[0] = Hlength(file_id, chk_rec->chk_tag, chk_rec->chk_ref);
2305 	        }
2306 	        count = 1;
2307 	    }   /* end if */
2308 	    else
2309 	    { /* this chunk is special */
2310 	        if (HPseek(file_rec, new_off) == FAIL)
2311 		    HGOTO_ERROR(DFE_SEEKERROR, FAIL);
2312 	        if (HP_read(file_rec, lbuf, (int)2) == FAIL)
2313 		    HGOTO_ERROR(DFE_READERROR, FAIL);
2314 
2315 	        /* Use special code to determine if additional specialness is
2316 		   compression */
2317 	        p = &lbuf[0];
2318 	        INT16DECODE(p, spec_code);
2319 
2320 		/* Chunk is compressed */
2321 	        if (spec_code == SPECIAL_COMP)
2322 	        {
2323 		    if (HP_read(file_rec, lbuf, (int)14) == FAIL)
2324 		        HGOTO_ERROR(DFE_READERROR, FAIL);
2325 
2326 		    p = &lbuf[0];
2327 		    p = p + 2 + 4;	/* skip version and _uncompressed_ data length */
2328 		    UINT16DECODE(p, comp_ref);/* get ref# of compressed data */
2329 
2330 		    /* Get the special info header */
2331 		    if (Hfind(file_id, DFTAG_COMPRESSED, comp_ref, &new_tag,&new_ref, &new_off,&new_len,DF_FORWARD)==FAIL)
2332 		        HE_REPORT_GOTO("Hfind failed ", FAIL);
2333 		    if ((cmpddid = HTPselect(file_rec, new_tag, new_ref)) == FAIL)
2334 		        HE_REPORT_GOTO("HTPselect failed ", FAIL);
2335 
2336 		    /* Check for further specialness */
2337 		    if (HTPis_special(cmpddid)!=TRUE)
2338 		    { /* this chunk is not further special, only compressed */
2339 		        if (offsetarray != NULL && lengtharray != NULL)
2340 		        {
2341 			    offsetarray[0] = new_off;
2342 			    lengtharray[0] = new_len;
2343 		        }
2344 		        count = 1;
2345 		    }   /* end if */
2346 		    else
2347 		    { /* this chunk is further special */
2348 		        if (HPseek(file_rec, new_off) == FAIL)
2349 			    HGOTO_ERROR(DFE_SEEKERROR, FAIL);
2350 		        if (HP_read(file_rec, lbuf, (int)2) == FAIL)
2351 			    HGOTO_ERROR(DFE_READERROR, FAIL);
2352 
2353                         /* Get the special code */
2354 		        p = &lbuf[0];
2355 		        INT16DECODE(p, spec_code);
2356 
2357                         /* If the special storage is in linked-blocks, use
2358                            HLgetdatainfo to get data info */
2359 		        if (spec_code == SPECIAL_LINKED)
2360 		        {
2361 			    if (HP_read(file_rec, lbuf, (int)14) == FAIL)
2362 			        HGOTO_ERROR(DFE_READERROR, FAIL);
2363 
2364 			    /* decode special information retrieved from file into info struct */
2365 			    p = &lbuf[0];
2366 
2367 			    /* get data information from the linked blocks */
2368 			    if (offsetarray != NULL && lengtharray != NULL)
2369 			        count = HLgetdatainfo(file_id, p, start_block, info_count, offsetarray, lengtharray);
2370 			    else
2371 			        count = HLgetdatainfo(file_id, p, start_block, 0, NULL, NULL);
2372 		        } /* this chunk is also stored in linked blocks */
2373 			/* May not be any other specialness, but we should flag
2374 			   it, so that if there is, we'll be aware of */
2375 			else
2376 			    HE_REPORT_GOTO("Compressed chunk has specialness other than linked-blocks", FAIL);
2377 		    } /* this element is further special */
2378 		    if (HTPendaccess(cmpddid) == FAIL)
2379 		        HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
2380 	        } /* spec_code is SPECIAL_COMP */
2381 
2382 		/* May not be any other specialness, but we should flag it, so
2383 		   that if there is, we'll be aware of */
2384 		else
2385 		    HE_REPORT_GOTO("Chunk has specialness other than compression", FAIL);
2386 	    } /* this chunk is special */
2387 	    if (HTPendaccess(ddid) == FAIL)
2388 	        HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
2389         } /* if valid chunk in file */
2390 
2391 	/* chunk record exists but chunk had not been written, could be error */
2392 	else
2393 	    HGOTO_ERROR(DFE_INTERNAL, FAIL);
2394     } /* chunk record exists */
2395 
2396     /* End access to the aid returned by Hstartread */
2397     if (Hendaccess(new_aid)==FAIL)
2398 	HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
2399 
2400     ret_value = count;
2401 
2402   done:
2403     if(ret_value == FAIL)
2404       { /* Error condition cleanup */
2405 
2406     /* End accesses */
2407     if (ddid != FAIL)
2408 	HTPendaccess(ddid);
2409     if (new_aid != FAIL)
2410 	Hendaccess(new_aid);
2411       } /* end if */
2412 
2413     /* Normal function cleanup */
2414     return ret_value;
2415 } /* HMCgetdatainfo */
2416 
2417 /*--------------------------------------------------------------------------
2418 NAME
2419      HMCgetdatasize - get data sizes of the chunked element
2420 
2421 DESCRIPTION
2422      This routine was intented to be used by HCPgetdatasize for the chunked
2423      element part.
2424 
2425      HMCgetdatasize proceeds as followed:
2426      - decode the chunking info special header to get the chunk table info
2427      - get access to the chunk table via Vdata interface
2428      - get the size of the chunk table to determine if the data has been written
2429      - if the element is also compressed, read each vdata record to obtain the
2430 	tag/ref pair of the compression special header and read the header
2431      - decode the compression special header to get the compressed data ref# and
2432 	retrieve the compressed data length via Hlength
2433      - if uncompressed size is requested by the caller, calculate the actual
2434 	size of the uncompressed data by (chunk size * number of records)
2435      - if compressed size is requested by the caller, calculate the total
2436 	compressed size by accumulating the compressed size of all chunks.
2437 
2438 RETURNS
2439      Returns SUCCEED/FAIL
2440 
2441 REVISION LOG
2442      September 2008: Added to fix bugzilla #587 - BMR
2443 
2444 -------------------------------------------------------------------------- */
2445 intn
HMCgetdatasize(int32 file_id,uint8 * p,int32 * comp_size,int32 * orig_size)2446 HMCgetdatasize(int32 file_id,
2447 		uint8 *p, /* IN: access id of header info */
2448 		int32 *comp_size, /* OUT: size of compressed data */
2449 		int32 *orig_size) /* OUT: size of uncompression type */
2450 {
2451     CONSTR(FUNC, "HMCgetdatasize");	/* for HERROR */
2452     uint16	 comp_ref = 0;		/* ref# of compressed data */
2453     char         vsname[VSNAMELENMAX + 1];  /* Vdata name */
2454     char         v_class[VSNAMELENMAX + 1] = ""; /* Vdata class for comparison */
2455     char         vsclass[VSNAMELENMAX + 1]; /* Vdata class */
2456     int32        vdata_size;		/* size of Vdata */
2457     chunkinfo_t* chkinfo=NULL;		/* chunked element information */
2458     uint8       *v_data = NULL;		/* Vdata record */
2459     int32        num_recs=0,		/* number of records in chunk table */
2460 		 chk_data_size=0,	/* non-compressed data size */
2461 		 chk_comp_data_size=0,	/* compressed data size */
2462 		 chktab_id=-1,		/* chunk table (vdata) id */
2463 		 chk_aid=-1,		/* a single chunk aid */
2464 		 len = 0;		/* length of a compressed chunk */
2465     uint8	 chk_spbuf[10];		/* 10 bytes for special tag, version,
2466 					   uncomp len, comp ref# */
2467     int		 j, k;
2468     intn	 ret_value = SUCCEED;
2469 
2470     /* Skip 4byte header len */
2471     p = p + 4;
2472 
2473     /* Allocate and fill in special chunk info struct for CHUNKs */
2474     if (( chkinfo = (chunkinfo_t *) HDmalloc(sizeof(chunkinfo_t)))==NULL)
2475         HGOTO_ERROR(DFE_NOSPACE, FAIL);
2476 
2477     /* Version info */
2478     HDmemcpy(&chkinfo->version, p, 1);      /* 1 byte  */
2479     p = p + 1;
2480 
2481     /* Should check version here to see if we can handle this version of
2482        special format header before we go on */
2483     if (chkinfo->version != _HDF_CHK_HDR_VER)
2484         HGOTO_ERROR(DFE_INTERNAL, FAIL);
2485 
2486     /* Flag indicating multiple specialness, used to find out if this element
2487        is also compressed or something else */
2488     INT32DECODE(p, chkinfo->flag);         /* 4 bytes */
2489 
2490     /* Length of uncompressed data as a whole, size of each chunk, and size of
2491        number type */
2492     INT32DECODE(p, chkinfo->length);       /* 4 bytes */
2493     INT32DECODE(p, chkinfo->chunk_size);   /* 4 bytes */
2494     INT32DECODE(p, chkinfo->nt_size);      /* 4 bytes */
2495 
2496     /* Get chunk data size */
2497     chk_data_size = chkinfo->chunk_size * chkinfo->nt_size;
2498 
2499     /* Get tag/ref of chunk table, 2 bytes each */
2500     UINT16DECODE(p, chkinfo->chktbl_tag);
2501     UINT16DECODE(p, chkinfo->chktbl_ref);
2502 
2503     /* Skip sp_tag and sp_ref then get ndims for use in skipping origins */
2504     p  = p + 2 + 2;
2505     INT32DECODE(p, chkinfo->ndims);        /* 4 bytes */
2506 
2507     /* Make sure it is really the vdata */
2508     if (chkinfo->chktbl_tag == DFTAG_VH)
2509     {
2510 	/* Use Vdata interface to access chunk table */
2511 
2512 	/* Start access on Vdata */
2513 	if(Vstart(file_id) == FAIL)
2514 	    HGOTO_ERROR(DFE_INTERNAL, FAIL);
2515 
2516 	/* Attach to the chunk table vdata and get its num of records */
2517 	if ((chktab_id = VSattach(file_id,(int32)chkinfo->chktbl_ref,"r")) == FAIL)
2518 	    HGOTO_ERROR(DFE_CANTATTACH, FAIL);
2519 
2520 	if ((VSinquire(chktab_id, &num_recs, NULL, NULL, &vdata_size, vsname)) == FAIL)
2521 	    HGOTO_ERROR(DFE_INTERNAL, FAIL);
2522 
2523 	/* Only continue reading the chunk table to get compressed data size
2524 	   if it is requested and if data had been written, i.e. chunk table is
2525 	   not empty */
2526 	if (comp_size != NULL && num_recs > 0)
2527 	{
2528 	    /* Check for further specialness.  If chunks are also compressed,
2529 	       then the chunk table will be read for each chunk's tag/ref,
2530 	       which points to the compression info of the chunk, to get the
2531 	       compressed data size */
2532 	    switch(chkinfo->flag & 0xff)
2533 	    {
2534 		/* Element is also compressed, read and decode the compression
2535 		   special info header of each chunk and get the compressed
2536 		   data size */
2537 		case SPECIAL_COMP:
2538 		{
2539 		    uint16     sp_tag;
2540 
2541 		    /* Get class of Vdata */
2542 		    if ((VSgetclass(chktab_id, vsclass)) == FAIL)
2543 			HGOTO_ERROR(DFE_INTERNAL, FAIL);
2544 
2545 		    /* Verify class and version */
2546 		    sprintf(v_class,"%s%d",_HDF_CHK_TBL_CLASS,_HDF_CHK_TBL_CLASS_VER);
2547 		    if (HDstrncmp(vsclass,v_class,HDstrlen(v_class)) != 0 )
2548 		    {
2549 			HGOTO_ERROR(DFE_INTERNAL, FAIL);
2550 		    }
2551 
2552 		    /* Set the fields to read */
2553 		    if(VSsetfields(chktab_id,_HDF_CHK_FIELD_NAMES)==FAIL)
2554 			HGOTO_ERROR(DFE_BADFIELDS,FAIL);
2555 
2556 		    /* Allocate space for a single Vdata record */
2557 		    if ((v_data = HDmalloc((size_t)vdata_size)) == NULL)
2558 			HGOTO_ERROR(DFE_NOSPACE, FAIL);
2559 
2560 		    /* Read in the tag/ref of each chunk then get the
2561 			compression info header the tag/ref points to and
2562 			decode the compressed data size */
2563 		    for (j = 0; j < num_recs; j++)
2564 		    {
2565 			uint8 *pntr = NULL;       /* temp pointer to vdata record */
2566 			uint16 chk_tag, chk_ref;  /* each chunk's tag/ref */
2567 
2568 			/* Read single record */
2569 			if(VSread(chktab_id,v_data,1,FULL_INTERLACE)==FAIL)
2570 			    HGOTO_ERROR(DFE_VSREAD,FAIL);
2571 
2572 			pntr = v_data; /* set pointer to vdata record */
2573 
2574 			/* Skip origin first */
2575 			for (k = 0; k < chkinfo->ndims; k++)
2576 			{
2577 			    pntr += sizeof(int32);
2578 			}
2579 
2580 			/* Get the chunk's tag and ref */
2581 			HDmemcpy(&chk_tag, pntr, sizeof(uint16));
2582 			pntr += sizeof(uint16);
2583 			HDmemcpy(&chk_ref, pntr, sizeof(uint16));
2584 
2585 			/* Prepare to read the info which the tag/ref points to */
2586 			chk_aid = Hstartaccess(file_id, MKSPECIALTAG(chk_tag), chk_ref, DFACC_READ);
2587 			if (chk_aid == FAIL)
2588 			    HGOTO_ERROR(DFE_BADAID, FAIL);
2589 
2590 			/* Read 10 bytes: special tag (2), comp. version (2),
2591 			   uncomp length (4), and comp. ref# (2) */
2592 			if (Hread(chk_aid, 10, chk_spbuf) == FAIL)
2593 			    HGOTO_ERROR(DFE_READERROR, FAIL);
2594 
2595 			/* Decode and check the special tag to be sure */
2596 			p = chk_spbuf;
2597 			UINT16DECODE(p, sp_tag);             /* 2 bytes */
2598 			if (sp_tag == SPECIAL_COMP)
2599 			{
2600 			    /* Skip compression version (2 bytes) and
2601 				uncompressed data length (4 bytes) */
2602 			    p = p + 2 + 4;
2603 
2604 			    /* Get ref # of compressed data (2 bytes) */
2605 			    UINT16DECODE(p, comp_ref);
2606 
2607 			    /* Get length of compressed data.  Note that this
2608 				length is specified as compressed chunk size
2609 				times nt_size. */
2610 			    if ((len = Hlength(file_id, DFTAG_COMPRESSED, comp_ref)) == FAIL)
2611 				HGOTO_ERROR(DFE_BADLEN, FAIL);
2612 
2613 			    /* Accumulate compressed size of all chunks. */
2614 			    chk_comp_data_size = chk_comp_data_size + len;
2615 			}
2616 
2617 			/* sp_tag is not SPECIAL_COMP, while 'chkinfo->flag'
2618 			   above is SPECIAL_COMP, something must be wrong */
2619 			else
2620 			    HGOTO_ERROR(DFE_COMPINFO, FAIL);
2621 
2622 			/* End access to special info of an individual chunk */
2623 			if(Hendaccess(chk_aid)==FAIL)
2624 			    HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
2625 		    } /* for each record */
2626 		    break;
2627 		}
2628 		default:
2629 		/* Element is not compressed, use non-compressed data size.
2630 		   Note: must multiply by num_recs here because when element is
2631 		   compressed, chk_comp_data_size was calculated by accumulating
2632 		   "len" of each compressed chunk (see case above) */
2633 		   chk_comp_data_size = chk_data_size * num_recs;
2634 	    } /* switch flag */
2635 	} /* if comp_size != NULL && num_recs >= 0 */
2636 
2637 	if (VSdetach(chktab_id) == FAIL)
2638 	    HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
2639 
2640     } /* it is a vdata */
2641     else
2642 	HGOTO_ERROR(DFE_INTERNAL, FAIL);
2643 
2644     /* Return requested sizes */
2645     if (comp_size != NULL)
2646 	*comp_size = chk_comp_data_size;
2647     if (orig_size != NULL)
2648 	*orig_size = chk_data_size * num_recs;
2649 
2650   done:
2651     if(ret_value == FAIL)
2652       { /* Error condition cleanup */
2653 
2654       } /* end if */
2655 
2656     /* Normal function cleanup */
2657     /* Free allocated space for vdata record */
2658     if (v_data != NULL)
2659         HDfree(v_data);
2660 
2661     /* Free special chunk info struct */
2662     if (chkinfo != NULL)
2663 	HDfree(chkinfo);
2664 
2665     return ret_value;
2666 } /* HMCgetdatasize */
2667 
2668 /*--------------------------------------------------------------------------
2669 NAME
2670      HMCsetMaxcache - maximum number of chunks to cache
2671 
2672 DESCRIPTION
2673      Set the maximum number of chunks to cache.
2674 
2675      The values set here affects the current object's caching behaviour.
2676 
2677      If the chunk cache is full and 'maxcache' is greater then the
2678      current 'maxcache' value, then the chunk cache is reset to the new
2679      'maxcache' value, else the chunk cache remains at the current
2680      'maxcache' value.
2681 
2682      If the chunk cache is not full, then the chunk cache is set to the
2683      new 'maxcache' value only if the new 'maxcache' value is greater than the
2684      current number of chunks in the cache.
2685 
2686      Use flags arguement of 'HMC_PAGEALL' if the whole object is to be cached
2687      in memory otherwise passs in zero.
2688 
2689 RETURNS
2690      Returns number of 'maxcache' if successful and FAIL otherwise
2691 
2692 AUTHOR
2693    -GeorgeV - 9/3/96
2694 
2695 NOTE
2696      This calls the real routine mcache_set_maxcache().
2697      Currently 'maxcache' has to be greater than 1.
2698 
2699 -------------------------------------------------------------------------- */
2700 int32
HMCsetMaxcache(int32 access_id,int32 maxcache,int32 flags)2701 HMCsetMaxcache(int32 access_id, /* IN: access aid to mess with */
2702                int32 maxcache,  /* IN: max number of pages to cache */
2703                int32 flags      /* IN: flags = 0, HMC_PAGEALL */)
2704 {
2705     CONSTR(FUNC, "HMCsetMaxcache");   /* for HERROR */
2706     accrec_t    *access_rec = NULL;   /* access record */
2707     chunkinfo_t *info       = NULL;   /* chunked element information record */
2708     int32       ret_value = SUCCEED;
2709 
2710     /* shut compiler up */
2711     flags=flags;
2712 
2713 #ifdef CHK_DEBUG_2
2714     fprintf(stderr,"HMCsetMaxcache: access_id =%d \n", access_id);
2715 #endif
2716     /* Check args */
2717     access_rec = HAatom_object(access_id);
2718     if (access_rec == NULL || maxcache < 1)
2719         HGOTO_ERROR(DFE_ARGS, FAIL);
2720 
2721 #ifdef CHK_DEBUG_2
2722     fprintf(stderr,"HMCsetMaxcache: access_rec->special =%d \n", access_rec->special);
2723     fprintf(stderr,"HMCsetMaxcache: access_rec->ddid =%d \n", access_rec->ddid);
2724 #endif
2725 
2726     /* since this routine can be called by the user,
2727        need to check if this access id is special CHUNKED */
2728     if (access_rec->special == SPECIAL_CHUNKED)
2729       {
2730           info     = (chunkinfo_t *) (access_rec->special_info);
2731 
2732           if (info != NULL)
2733               ret_value =  mcache_set_maxcache(info->chk_cache,maxcache);
2734           else
2735               ret_value = FAIL;
2736       }
2737     else /* not special */
2738         ret_value = FAIL;
2739 
2740   done:
2741     if(ret_value == FAIL)
2742       { /* Error condition cleanup */
2743 
2744       } /* end if */
2745 
2746     /* Normal function cleanup */
2747     return ret_value;
2748 } /* HMCsetMaxcache() */
2749 
2750 /* ------------------------------ HMCPstread -------------------------------
2751 NAME
2752    HMCPstread -- open an access record of chunked element for reading
2753 
2754 DESCRIPTION
2755    Calls to HMCIstaccess to fill in the access rec for
2756    reading
2757 
2758 RETURNS
2759    The AID of the access record on success FAIL on error.
2760 AUTHOR
2761    -GeorgeV - 9/3/96
2762 ---------------------------------------------------------------------------*/
2763 int32
HMCPstread(accrec_t * access_rec)2764 HMCPstread(accrec_t * access_rec /* IN: access record to fill in */)
2765 {
2766     int32 ret_value;
2767 
2768     ret_value = HMCIstaccess(access_rec, DFACC_READ);
2769 
2770     return ret_value;
2771 }   /* HMCPstread */
2772 
2773 /* ------------------------------ HMCPstwrite ------------------------------
2774 NAME
2775    HMCPstwrite -- open an access record of a chunked elmenent for writing
2776 
2777 DESCRIPTION
2778    Calls to HMCIstaccess to fill in the access rec for
2779    writing
2780 
2781 RETURNS
2782    The AID of the access record on success FAIL on error.
2783 AUTHOR
2784    -GeorgeV - 9/3/96
2785 ---------------------------------------------------------------------------*/
2786 int32
HMCPstwrite(accrec_t * access_rec)2787 HMCPstwrite(accrec_t * access_rec /* IN: access record to fill in */)
2788 {
2789     int32  ret_value;
2790 
2791     ret_value = HMCIstaccess(access_rec, DFACC_WRITE);
2792 
2793     return ret_value;
2794 }   /* HMCPstwrite */
2795 
2796 
2797 /* ------------------------------- HMCPseek --------------------------------
2798 NAME
2799    HMCPseek -- set the seek posn in the chunked elemnent
2800 
2801 DESCRIPTION
2802    Set the seek posn in the given chunked element
2803 
2804 RETURNS
2805    SUCCEED / FAIL
2806 AUTHOR
2807    -GeorgeV - 9/3/96
2808 ---------------------------------------------------------------------------*/
2809 int32
HMCPseek(accrec_t * access_rec,int32 offset,int origin)2810 HMCPseek(accrec_t * access_rec,  /* IN: access record to mess with */
2811          int32 offset,           /* IN: seek offset */
2812          int origin              /* IN: where we should calc the offset from */)
2813 {
2814     CONSTR(FUNC, "HMCPseek");    /* for HERROR */
2815     chunkinfo_t *info = NULL;    /* information for the chunked elt */
2816     int32   ret_value = SUCCEED;
2817 
2818 #ifdef CHK_DEBUG_3
2819     printf("HMCPseek called with offset %d \n",offset);
2820 #endif
2821     /* Check args */
2822     if (access_rec == NULL)
2823         HGOTO_ERROR(DFE_ARGS, FAIL);
2824 
2825     /* validate access record */
2826     if (access_rec->special != SPECIAL_CHUNKED)
2827         HGOTO_ERROR(DFE_INTERNAL, FAIL);
2828 
2829     /* get special info */
2830     info = (chunkinfo_t *) (access_rec->special_info);
2831 
2832     /* adjust the offset according to origin and validate */
2833     /* there is no upper bound to posn */
2834     if (origin == DF_CURRENT)
2835         offset += access_rec->posn;
2836     if (origin == DF_END)
2837         offset += (info->length * info->nt_size); /* adjust by number type size */
2838     if (offset < 0)
2839         HGOTO_ERROR(DFE_RANGE, FAIL);
2840 
2841     /* Seek to given location(bytes) for reading/writing */
2842     /* i.e calculate chunk indices given seek location
2843        this will update the proper arrays in the special info struct */
2844     update_chunk_indicies_seek(offset,info->ndims, info->nt_size,
2845                                info->seek_chunk_indices,
2846                                info->seek_pos_chunk,info->ddims);
2847 
2848     /* set position in access record */
2849     access_rec->posn = offset;
2850 
2851 #ifdef CHK_DEBUG_3
2852     printf("HMCPseek new user seek postion in element is  %d \n",offset);
2853 #endif
2854 
2855   done:
2856     if(ret_value == FAIL)
2857       { /* Error condition cleanup */
2858 
2859       } /* end if */
2860 
2861     /* Normal function cleanup */
2862     return ret_value;
2863 }   /* HMCPseek */
2864 
2865 /* ------------------------------- HMCPchunkread --------------------------------
2866 NAME
2867    HMCPchunkread - read a chunk
2868 
2869 DESCRIPTION
2870    Read in a whole chunk from a chunked element given the chunk number.
2871 
2872    This is used as the 'page-in-chunk' routine for the cache.
2873    Only the cache should call this routine.
2874 
2875 RETURNS
2876    The number of bytes read or FAIL on error
2877 AUTHOR
2878    -GeorgeV - 9/3/96
2879 --------------------------------------------------------------------------- */
2880 int32
HMCPchunkread(void * cookie,int32 chunk_num,void * datap)2881 HMCPchunkread(void  *cookie,    /* IN: access record to mess with */
2882               int32 chunk_num,  /* IN: chunk to read */
2883               void  *datap      /* OUT: buffer for data */)
2884 {
2885     CONSTR(FUNC, "HMCPchunkread");    /* for HERROR */
2886     accrec_t * access_rec = (accrec_t *)cookie; /* access record */
2887     chunkinfo_t *info    = NULL; /* information record for this special data elt */
2888     CHUNK_REC   *chk_rec = NULL; /* chunk record */
2889     TBBT_NODE   *entry   = NULL; /* chunk node from TBBT */
2890     uint8       *bptr    = NULL; /* pointer to data buffer */
2891     int32       chk_id   = FAIL; /* chunk id */
2892     int32       bytes_read = 0;    /* total # bytes read for this call of HMCIread */
2893     int32       read_len = 0;      /* length of bytes to read */
2894     int32       nitems = 1;        /* used in HDmemfill(), */
2895     int32       ret_value = SUCCEED;
2896 
2897     /* Check args */
2898     if (access_rec == NULL)
2899         HGOTO_ERROR(DFE_ARGS, FAIL);
2900 
2901     /* set inputs */
2902     bptr = (uint8 *) datap;
2903     info = (chunkinfo_t *) (access_rec->special_info);
2904     bytes_read    = 0;
2905     read_len      = (info->chunk_size * info->nt_size);
2906 
2907 #ifdef CHK_DEBUG_3
2908     printf("HMCPchunkread called with chunk %d \n",chunk_num);
2909 #endif
2910     /* find chunk record in TBBT */
2911     if ((entry = (tbbtdfind(info->chk_tree, &chunk_num, NULL))) == NULL)
2912       { /* does not exist */
2913           /* calculate number of fill value items to fill buffer with */
2914           nitems = (info->chunk_size * info->nt_size) / info->fill_val_len;
2915 
2916           /* copy fill values into buffer and return */
2917           if (HDmemfill(datap,info->fill_val, (uint32)info->fill_val_len,(uint32)nitems) == NULL)
2918               HE_REPORT_GOTO("HDmemfill failed to fill read chunk", FAIL);
2919       }
2920     else /* exists in TBBT */
2921       {
2922           /* get chunk record from node */
2923           chk_rec = (CHUNK_REC *) entry->data;
2924 
2925           /* check to see if has been written to */
2926           if (chk_rec->chk_tag != DFTAG_NULL && BASETAG(chk_rec->chk_tag) == DFTAG_CHUNK)
2927             { /* valid chunk in file */
2928                 /* Start read on chunk */
2929                 if ((chk_id = Hstartread(access_rec->file_id, chk_rec->chk_tag,
2930                                          chk_rec->chk_ref)) == FAIL)
2931                   {
2932                       Hendaccess(chk_id);
2933                       HE_REPORT_GOTO("Hstartread failed to read chunk", FAIL);
2934                   }
2935 
2936                 /* read data from chunk */
2937                 if (Hread(chk_id, read_len, bptr) == FAIL)
2938                     HGOTO_ERROR(DFE_READERROR, FAIL);
2939 
2940                 bytes_read = read_len;
2941 
2942                 /* end access to chunk */
2943                 if (Hendaccess(chk_id) == FAIL)
2944                     HE_REPORT_GOTO("Hendaccess failed to end access to chunk", FAIL);
2945 
2946             }
2947           else if (chk_rec->chk_tag == DFTAG_NULL)
2948             {/* chunk has not been written, so return fill value buffer */
2949                 /* calculate number of fill value items to fill buffer with */
2950                 nitems = (info->chunk_size * info->nt_size) / info->fill_val_len;
2951 
2952                 /* copy fill values into buffer and return */
2953                 if (HDmemfill(datap,info->fill_val, (uint32)info->fill_val_len,(uint32)nitems) == NULL)
2954                     HE_REPORT_GOTO("HDmemfill failed to fill read chunk", FAIL);
2955             }
2956           else /* not a valid chunk ref for now */
2957             {
2958                 /* For now DFTAG_CHUNK is the only allowed value.
2959                    In the future this could be another Chunk table. */
2960                 HE_REPORT_GOTO("Not a valid Chunk object, wrong tag for chunk", FAIL);
2961             }
2962 
2963       } /* end else exists in TBBT tree */
2964 
2965     ret_value = bytes_read; /* number of bytes read */
2966 
2967   done:
2968     if(ret_value == FAIL)
2969       { /* Error condition cleanup */
2970           if (chk_id != FAIL)
2971               Hendaccess(chk_id);
2972       } /* end if */
2973 
2974     /* Normal function cleanup */
2975 #ifdef CHK_DEBUG_3
2976     printf("HMCPchunkread exit with ret_value= %d \n",ret_value);
2977 #endif
2978     return ret_value;
2979 } /* HMCPchunkread() */
2980 
2981 /* ------------------------------- HMCreadChunk ---------------------------
2982 NAME
2983    HMCreadChunk -- read a whole chunk
2984 
2985 DESCRIPTION
2986    Read a whole chunk from a chunked element.
2987 
2988    This can be used by users to read whole chunks from the file
2989    based on chunk origin for now i.e postion of chunk in overall
2990 .  chunk array.
2991 
2992 RETURNS
2993    The number of bytes read or FAIL on error
2994 AUTHOR
2995    -GeorgeV - 9/3/96
2996 ---------------------------------------------------------------------------*/
2997 int32
HMCreadChunk(int32 access_id,int32 * origin,void * datap)2998 HMCreadChunk(int32 access_id,  /* IN: access aid to mess with */
2999              int32 *origin,    /* IN: origin of chunk to read */
3000              void *datap /* IN: buffer for data */)
3001 {
3002     CONSTR(FUNC, "HMCreadChunk");  /* for HERROR */
3003     accrec_t    *access_rec = NULL; /* access record */
3004 #ifdef UNUSED
3005     uint8       *data       = NULL; /* data buffer */
3006 #endif /* UNUSED */
3007     filerec_t   *file_rec   = NULL; /* file record */
3008     chunkinfo_t *info       = NULL; /* chunked element information record */
3009     uint8       *bptr       = NULL; /* data buffer pointer */
3010     void        *chk_data   = NULL; /* chunk data */
3011     uint8       *chk_dptr   = NULL; /* chunk data pointer */
3012     int32       relative_posn;      /* relative position in chunked element */
3013     int32       bytes_read = 0;     /* total #bytes read  */
3014     int32       read_len = 0;       /* bytes to read next */
3015     int32       chunk_num = -1;     /* chunk number */
3016     int32       ret_value = SUCCEED;
3017     intn        i;
3018 
3019 #ifdef CHK_DEBUG_5
3020     printf("HMCreadChunk: entered \n");
3021 #endif
3022     /* Check args */
3023     access_rec = HAatom_object(access_id);
3024     if (access_rec == NULL)
3025         HGOTO_ERROR(DFE_ARGS, FAIL);
3026 
3027     if (origin == NULL || datap == NULL)
3028         HGOTO_ERROR(DFE_ARGS, FAIL);
3029 
3030     /* validate file records */
3031     file_rec =  HAatom_object(access_rec->file_id);
3032     if (BADFREC(file_rec))
3033         HGOTO_ERROR(DFE_INTERNAL, FAIL);
3034 
3035     /* can read from this file? */
3036     if (!(file_rec->access & DFACC_READ))
3037         HGOTO_ERROR(DFE_DENIED, FAIL);
3038 
3039     /* since this routine can be called by the user,
3040        need to check if this access id is special CHUNKED */
3041     if (access_rec->special == SPECIAL_CHUNKED)
3042       {
3043           /* Set inputs */
3044 #ifdef UNUSED
3045           data     = (uint8 *) datap;
3046 #endif /* UNUSED */
3047           info     = (chunkinfo_t *) (access_rec->special_info);
3048           relative_posn = access_rec->posn;
3049           read_len      = (info->chunk_size * info->nt_size);
3050           bytes_read    = 0;
3051           bptr          = datap;
3052 
3053           /* copy origin over to seek chunk indicies
3054              and set position within chunk to beginning of that chunk */
3055           for (i = 0; i < info->ndims; i++)
3056             {
3057               info->seek_chunk_indices[i] = origin[i];
3058               info->seek_pos_chunk[i] = 0;
3059             }
3060 
3061 #ifdef CHK_DEBUG_5
3062           printf(" Seek start(in chunk array):(");
3063           for (i = 0; i < info->ndims; i++)
3064               printf("%d%s", info->seek_chunk_indices[i], i!= info->ndims-1 ? ",":NULL);
3065           printf(")\n");
3066 #endif
3067           /* calculate chunk number from origin */
3068           calculate_chunk_num(&chunk_num, info->ndims, origin, info->ddims);
3069 
3070 #ifdef CHK_DEBUG_5
3071     printf("HMCreadChunk called with chunk %d \n",chunk_num);
3072 #endif
3073           /* currently get chunk data from cache based on chunk number
3074              Note the cache deals with objects starting from 1 not 0 */
3075           if ((chk_data = mcache_get(info->chk_cache, /* cache handle */
3076                                               chunk_num+1,     /* chunk number */
3077                                               0                /* flag: unused */))
3078               == NULL)
3079               HE_REPORT_GOTO("failed to find chunk record", FAIL);
3080 
3081           chk_dptr = chk_data; /* set chunk data ptr */
3082 
3083           /* copy data from chunk to users buffer */
3084           HDmemcpy(bptr, chk_dptr, read_len);
3085 
3086           /* put chunk back to cache and mark it as *not* DIRTY */
3087           if (mcache_put(info->chk_cache, /* cache handle */
3088                          chk_data,        /* whole data chunk */
3089                          0                /* flag: 0->not DIRTY */)
3090               == FAIL)
3091               HE_REPORT_GOTO("failed to put chunk back in cache", FAIL);
3092 
3093           /* adjust number of bytes already read */
3094           bytes_read = read_len;
3095 
3096 #ifdef CHK_DEBUG_5
3097           printf("HMCreadChunk: read %d bytes already\n", bytes_read);
3098 #endif
3099 
3100           /*update chunk seek indicies after reading chunk */
3101           update_seek_pos_chunk(bytes_read,info->ndims,info->nt_size,
3102                                 info->seek_pos_chunk,
3103                                 info->ddims);
3104 
3105           /* compute user array for chunk arrays */
3106           compute_chunk_to_array(info->seek_chunk_indices,info->seek_pos_chunk,
3107                                  info->seek_user_indices,
3108                                  info->ndims,info->ddims);
3109 
3110           /* calculate new read seek postion in element from user array */
3111           compute_array_to_seek(&relative_posn,
3112                                  info->seek_user_indices,
3113                                  info->nt_size,info->ndims,info->ddims);
3114 
3115 #ifdef CHK_DEBUG_5
3116           printf("HMCreadChunk: new postion in element is %d\n", relative_posn);
3117 #endif
3118           /* update access record with bytes read */
3119           access_rec->posn = relative_posn;
3120 
3121 #ifdef CHK_DEBUG_5
3122           /* for info only */
3123           compute_chunk_to_seek(&relative_posn,info->ndims,info->nt_size,
3124                                info->seek_chunk_indices,
3125                                info->seek_pos_chunk,info->ddims,
3126                                info->chunk_size);
3127           printf("HMCreadChunk: new chunk seek postion in element is %d\n", relative_posn);
3128 #endif
3129 
3130           ret_value = bytes_read;
3131       }
3132     else /* not special chunked element */
3133         ret_value = FAIL;
3134 
3135   done:
3136     if(ret_value == FAIL)
3137       { /* Error condition cleanup */
3138       } /* end if */
3139 
3140     /* Normal function cleanup */
3141 
3142 #ifdef CHK_DEBUG_5
3143     printf("HMCreadChunk: exited, ret=%d \n",ret_value);
3144 #endif
3145     return ret_value;
3146 } /* HMCreadChunk() */
3147 
3148 /* ------------------------------- HMCPread --------------------------------
3149 NAME
3150    HMCPread - read data from a chunked element
3151 
3152 DESCRIPTION
3153    Read in some data from a chunked element.
3154 
3155    Data is obtained from the cache which takes care of reading
3156    in the proper chunks to satisfy the request.
3157 
3158 RETURNS
3159    The number of bytes read or FAIL on error
3160 AUTHOR
3161    -GeorgeV - 9/3/96
3162 --------------------------------------------------------------------------- */
3163 int32
HMCPread(accrec_t * access_rec,int32 length,void * datap)3164 HMCPread(accrec_t * access_rec, /* IN: access record to mess with */
3165          int32 length,          /* IN: number of bytes to read */
3166          void * datap            /* OUT: buffer for data */)
3167 {
3168     CONSTR(FUNC, "HMCPread");    /* for HERROR */
3169 #ifdef UNUSED
3170     uint8       *data = NULL;    /* data buffer */
3171 #endif /* UNUSED */
3172     chunkinfo_t *info = NULL;    /* information record for this special data elt */
3173     int32       relative_posn = 0; /* relative position in chunk of data elt */
3174     int32       bytes_read = 0;  /* total # bytes read for this call of HMCIread */
3175     uint8       *bptr = NULL;    /* data buffer pointer */
3176     int32       read_len = 0;    /* amount of data to copy */
3177     int32       read_seek = 0;   /* next read seek position */
3178     int32       chunk_size = 0;  /* size of data to read from chunk */
3179     int32       chunk_num = 0;   /* next chunk number */
3180     void        *chk_data = NULL; /* chunk data */
3181     uint8       *chk_dptr = NULL; /* pointer to chunk data */
3182 #ifdef CHK_DEBUG_3
3183     int         i;
3184 #endif
3185     int32       ret_value = SUCCEED;
3186 
3187 #ifdef CHK_DEBUG_3
3188     printf("HMCPread called with length %d \n",length);
3189 #endif
3190     /* Check args */
3191     if (access_rec == NULL)
3192         HGOTO_ERROR(DFE_ARGS, FAIL);
3193 
3194 #ifdef CHK_DEBUG_2
3195     fprintf(stderr,"HMCread: access_rec->special =%d \n", access_rec->special);
3196     fprintf(stderr,"HMCread: access_rec->ddid =%d \n", access_rec->ddid);
3197 #endif
3198 
3199     /* set inputs */
3200 #ifdef UNUSED
3201     data = (uint8 *) datap;
3202 #endif /* UNUSED */
3203     info = (chunkinfo_t *) (access_rec->special_info);
3204     relative_posn = access_rec->posn; /* current seek postion in element */
3205 
3206     /* validate length and set proper length */
3207     if (length == 0)
3208         length = (info->length * info->nt_size) - access_rec->posn;
3209     else if (length < 0)
3210         HGOTO_ERROR(DFE_RANGE, FAIL);
3211 
3212     if (access_rec->posn + length > (info->length * info->nt_size))
3213         length = (info->length * info->nt_size) - access_rec->posn;
3214 
3215     /* should chunk indicies be updated with relative_posn?
3216        or did last operation update it already */
3217     update_chunk_indicies_seek(access_rec->posn,info->ndims, info->nt_size,
3218                                info->seek_chunk_indices,
3219                                info->seek_pos_chunk,info->ddims);
3220 
3221     /* enter translating length to proper filling of buffer from chunks */
3222     bptr = datap;
3223     bytes_read = 0;
3224     read_len = length;
3225     while (bytes_read < read_len)
3226       {
3227           /* for debuging */
3228 #ifdef CHK_DEBUG_3
3229 	  int i;
3230           printf(" Seek start(in chunk array):(");
3231           for (i = 0; i < info->ndims; i++)
3232               printf("%d%s", info->seek_chunk_indices[i], i!= info->ndims-1 ? ",":NULL);
3233           printf(")\n");
3234           printf(" Seek start(within the chunk):(");
3235           for (i = 0; i < info->ndims; i++)
3236               printf("%d%s", info->seek_pos_chunk[i], i!= info->ndims-1 ? ",":NULL);
3237           printf(")\n");
3238 #endif
3239 
3240           /* calculate chunk to retrieve on this pass */
3241           calculate_chunk_num(&chunk_num,info->ndims,info->seek_chunk_indices,
3242                               info->ddims);
3243 
3244           /* calculate contiguous chunk size that we can read from this chunk
3245              during this pass */
3246           calculate_chunk_for_chunk(&chunk_size,info->ndims,info->nt_size,
3247                                     read_len,bytes_read,
3248                                     info->seek_chunk_indices,
3249                                     info->seek_pos_chunk,info->ddims);
3250 
3251           /* would be nice to get Chunk record from TBBT based on chunk number
3252              and then get chunk data base on chunk vdata number but
3253              currently the chunk calculations return chunk
3254              numbers and not Vdata record numbers.
3255              This would reduce some overhead in the number of chunks
3256              dealt with in the cache */
3257 
3258           /* currently get chunk data from cache based on chunk number
3259              Note the cache deals with objects starting from 1 not 0 */
3260           if ((chk_data = mcache_get(info->chk_cache, /* cache handle */
3261                                               chunk_num+1,     /* chunk number */
3262                                               0                /* flag: unused */))
3263               == NULL)
3264               HE_REPORT_GOTO("failed to find chunk record", FAIL);
3265 
3266           chk_dptr = chk_data; /* set chunk data ptr */
3267 
3268           /* calculate position in chunk */
3269           calculate_seek_in_chunk(&read_seek,info->ndims,info->nt_size,
3270                                   info->seek_pos_chunk,
3271                                   info->ddims);
3272 
3273           chk_dptr += read_seek; /* move to correct position in chunk */
3274 
3275 #ifdef CHK_DEBUG_3
3276           printf("  read pos in chunk(%d) is %d bytes\n", chunk_num, read_seek);
3277 #endif
3278           /* copy data from chunk to users buffer */
3279           HDmemcpy(bptr, chk_dptr, chunk_size);
3280 
3281 #ifdef CHK_DEBUG_10
3282           printf(" chk_dptr={");
3283           for (i = 0; i < chunk_size; i++)
3284               printf("%d,",(uint8)*((uint8 *)(chk_dptr)+i));
3285           printf("}\n");
3286 #endif
3287           /* put chunk back to cache */
3288           if (mcache_put(info->chk_cache, /* cache handle */
3289                          chk_data,        /* whole data chunk */
3290                          0                /* flag: 0->not DIRTY */)
3291               == FAIL)
3292               HE_REPORT_GOTO("failed to put chunk back in cache", FAIL);
3293 
3294           /* increment buffer pointer */
3295           bptr += chunk_size;
3296 
3297           /* adjust number of bytes already read */
3298           bytes_read += chunk_size;
3299 
3300 #ifdef CHK_DEBUG_3
3301           printf("  read %d bytes already\n", bytes_read);
3302 #endif
3303           /* update relative position i.e. user element seek postion
3304              with chunk size written */
3305           relative_posn += chunk_size;
3306 #ifdef CHK_DEBUG_3
3307           printf("  relative_posn = %d bytes \n", relative_posn);
3308 #endif
3309           /* i.e calculate chunk indices given seek location
3310              this will update the proper arrays in the special info struct */
3311           update_chunk_indicies_seek(relative_posn,info->ndims, info->nt_size,
3312                                      info->seek_chunk_indices,
3313                                      info->seek_pos_chunk,info->ddims);
3314       } /* end while "bytes_read" */
3315 
3316     /* update access record postion with bytes read */
3317     access_rec->posn += bytes_read;
3318 
3319     ret_value = bytes_read;
3320 
3321 #ifdef CHK_DEBUG_10
3322     printf(" datap={");
3323     for (i = 0; i < length; i++)
3324         printf("%d,",(uint8)*((uint8 *)(datap)+i));
3325     printf("}\n");
3326 #endif
3327   done:
3328     if(ret_value == FAIL)
3329       { /* Error condition cleanup */
3330 
3331       } /* end if */
3332 
3333     /* Normal function cleanup */
3334     return ret_value;
3335 }   /* HMCPread  */
3336 
3337 /* ------------------------------- HMCPchunkwrite -------------------------------
3338 NAME
3339    HMCPchunkwrite -- write out chunk
3340 
3341 DESCRIPTION
3342    Write a whole chunk to a chunked element given the chunk number.
3343 
3344    This is used as the 'page-out-chunk' routine for the cache.
3345    Only the cache should call this routine.
3346 
3347 RETURNS
3348    The number of bytes written or FAIL on error
3349 AUTHOR
3350    -GeorgeV - 9/3/96
3351 ---------------------------------------------------------------------------*/
3352 int32
HMCPchunkwrite(void * cookie,int32 chunk_num,const void * datap)3353 HMCPchunkwrite(void  *cookie,    /* IN: access record to mess with */
3354                int32 chunk_num,  /* IN: chunk number */
3355                const void *datap /* IN: buffer for data */)
3356 {
3357     CONSTR(FUNC, "HMCPchunkwrite");   /* for HERROR */
3358     accrec_t * access_rec = (accrec_t *)cookie; /* access record */
3359     chunkinfo_t *info    = NULL;  /* chunked element information record */
3360     CHUNK_REC   *chk_rec = NULL;  /* current chunk */
3361     TBBT_NODE   *entry   = NULL;  /* node off of  chunk tree */
3362     uint8       *v_data  = NULL;  /* chunk table record i.e Vdata record */
3363     CHUNK_REC   *chkptr  = NULL;  /* Chunk record to inserted in TBBT  */
3364     const void  *bptr    = NULL;  /* data buffer pointer */
3365     int32       chk_id   = FAIL ; /* chunkd accces id */
3366 #ifdef UNUSED
3367     uint8      *data     = NULL;  /* data buffer */
3368     int32       relative_posn;     /* relative position in chunked element */
3369 #endif /* UNUSED */
3370     int32       bytes_written = 0; /* total #bytes written by HMCIwrite */
3371     int32       write_len = 0;     /* nbytes to write next */
3372     int32       ret_value = SUCCEED;
3373     intn        k;                 /* loop index */
3374 
3375     /* Check args */
3376     if (access_rec == NULL)
3377         HGOTO_ERROR(DFE_ARGS, FAIL);
3378 
3379     /* Set inputs */
3380     info     = (chunkinfo_t *) (access_rec->special_info);
3381 #ifdef UNUSED
3382     data     = (uint8 *) datap;
3383     relative_posn = access_rec->posn;
3384 #endif /* UNUSED */
3385     write_len     = (info->chunk_size * info->nt_size);
3386     bytes_written = 0;
3387     bptr          = datap;
3388 
3389 #ifdef CHK_DEBUG_4
3390     printf("HMCPchunkwrite called with chunk %d \n",chunk_num);
3391 #endif
3392     /* find chunk record in TBBT */
3393     if ((entry = (tbbtdfind(info->chk_tree, &chunk_num, NULL))) == NULL)
3394         HE_REPORT_GOTO("failed to find chunk record", FAIL);
3395 
3396     chk_rec = (CHUNK_REC *) entry->data; /* get file entry from node */
3397 
3398     /* Check to see if already created in chunk table */
3399     if (chk_rec->chk_tag == DFTAG_NULL)
3400       { /* does not exists in Vdata table and in file but does in TBBT */
3401           uint8 *pntr = NULL;
3402 
3403           chkptr = chk_rec;
3404           /* so create a new Vdata record */
3405           /* Allocate space for a single Chunk record in Vdata */
3406           if (v_data == NULL)
3407             {
3408                 if ((v_data = HDmalloc(((size_t)info->ndims*sizeof(int32))
3409                                                + (2*sizeof(uint16)))) == NULL)
3410                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3411             }
3412 
3413           /* Initialize chunk record */
3414           chkptr->chk_tag = DFTAG_CHUNK;
3415           chkptr->chk_ref = Htagnewref(access_rec->file_id, DFTAG_CHUNK);
3416 #ifdef CHK_DEBUG_4
3417           printf(" chktpr->chk_tag=%d, ",chkptr->chk_tag);
3418           printf(" chktpr->chk_ref=%d, ",chkptr->chk_ref);
3419           printf(" chkptr->origin = (");
3420           for (k = 0; k < info->ndims; k++)
3421               printf("%d%s", chkptr->origin[k], k!= info->ndims-1 ? ",":NULL);
3422           printf(")\n");
3423 #endif
3424 
3425           if (chkptr->chk_ref == 0) {
3426                     /* out of ref numbers -- extremely fatal  */
3427                     HGOTO_ERROR(DFE_NOREF, FAIL);
3428           }
3429           /* Copy origin first to vdata record*/
3430           pntr = v_data;
3431           for (k = 0; k < info->ndims; k++)
3432             {
3433                 HDmemcpy(pntr, &chkptr->origin[k],sizeof(int32));
3434                 pntr += sizeof(int32);
3435             }
3436 
3437           /* Copy tag next */
3438           HDmemcpy(pntr, &chkptr->chk_tag,sizeof(uint16));
3439           pntr += sizeof(uint16);
3440 
3441           /* Copy ref last */
3442           HDmemcpy(pntr, &chkptr->chk_ref,sizeof(uint16));
3443 
3444           /* Add to Vdata i.e. chunk table */
3445           if(VSwrite(info->aid,v_data,1,FULL_INTERLACE)==FAIL)
3446               HGOTO_ERROR(DFE_VSWRITE,FAIL);
3447 
3448           /* Create compressed chunk if set
3449              else start write access on element */
3450           switch(info->flag & 0xff) /* only using 8bits for now */
3451             {
3452             case SPECIAL_COMP: /* Create compressed chunk */
3453                 if ((chk_id = HCcreate(access_rec->file_id, chk_rec->chk_tag,
3454                                        chk_rec->chk_ref,
3455                                        info->model_type, info->minfo,
3456                                        info->comp_type, info->cinfo)) == FAIL)
3457                     HE_REPORT_GOTO("HCcreate failed to read chunk", FAIL);
3458                 break;
3459             default:
3460                 /* Start write on chunk */
3461                 if ((chk_id = Hstartwrite(access_rec->file_id, chk_rec->chk_tag,
3462                                           chk_rec->chk_ref,write_len)) == FAIL)
3463                     HE_REPORT_GOTO("Hstartwrite failed to read chunk", FAIL);
3464                 break;
3465             }
3466       } /* not already in Vdata table */
3467     else
3468       { /* Already in table so start access */
3469         /* Start write on chunk */
3470         if ((chk_id = Hstartwrite(access_rec->file_id, chk_rec->chk_tag,
3471                                   chk_rec->chk_ref,write_len)) == FAIL)
3472             HE_REPORT_GOTO("Hstartwrite failed to read chunk", FAIL);
3473       }
3474 
3475     /* write data to chunk */
3476     if (Hwrite(chk_id, write_len, bptr) == FAIL)
3477         HGOTO_ERROR(DFE_WRITEERROR, FAIL);
3478 
3479     bytes_written = write_len;
3480 
3481     /* end access to chunk */
3482     if (Hendaccess(chk_id) == FAIL)
3483         HE_REPORT_GOTO("Hendaccess failed to end access to chunk", FAIL);
3484 
3485     ret_value = bytes_written;
3486 
3487   done:
3488     if(ret_value == FAIL)
3489       { /* Error condition cleanup */
3490           if (chk_id != FAIL)
3491               Hendaccess(chk_id);
3492       } /* end if */
3493 
3494     /* Normal function cleanup */
3495     if (v_data != NULL)
3496         HDfree(v_data);
3497 
3498 #ifdef CHK_DEBUG_4
3499     printf("HMCPchunkwrite exited with ret_value %d \n",ret_value);
3500 #endif
3501     return ret_value;
3502 } /* HMCPchunkwrite() */
3503 
3504 /* ------------------------------- HMCwriteChunk ---------------------------
3505 NAME
3506    HMCwriteChunk -- write out a whole chunk
3507 
3508 DESCRIPTION
3509    Write out some data from a chunked element.
3510 
3511    This can be used by users to write whole chunks to the file
3512    based on chunk origin for now i.e position of chunk in overall
3513    chunk array.
3514 
3515 RETURNS
3516    The number of bytes written or FAIL on error
3517 AUTHOR
3518    -GeorgeV - 9/3/96
3519 ---------------------------------------------------------------------------*/
3520 int32
HMCwriteChunk(int32 access_id,int32 * origin,const void * datap)3521 HMCwriteChunk(int32 access_id,  /* IN: access aid to mess with */
3522               int32 *origin,    /* IN: origin of chunk to write */
3523               const void *datap /* IN: buffer for data */)
3524 {
3525     CONSTR(FUNC, "HMCwriteChunk");  /* for HERROR */
3526     accrec_t    *access_rec = NULL; /* access record */
3527 #ifdef UNUSED
3528     uint8       *data       = NULL; /* data buffer */
3529     CHUNK_REC   *chk_rec    = NULL; /* current chunk */
3530     TBBT_NODE   *entry      = NULL; /* node off of  chunk tree */
3531 #endif /* UNUSED */
3532     filerec_t   *file_rec   = NULL; /* file record */
3533     chunkinfo_t *info       = NULL; /* chunked element information record */
3534     CHUNK_REC   *chkptr     = NULL; /* Chunk record to inserted in TBBT  */
3535     int32       *chk_key    = NULL; /* Chunk recored key for insertion in TBBT */
3536     const void  *bptr       = NULL; /* data buffer pointer */
3537     void        *chk_data   = NULL; /* chunk data */
3538     uint8       *chk_dptr   = NULL; /* chunk data pointer */
3539     int32       relative_posn;      /* relative position in chunked element */
3540     int32       bytes_written = 0;  /* total #bytes written by HMCIwrite */
3541     int32       write_len = 0;      /* bytes to write next */
3542     int32       chunk_num = -1;     /* chunk number */
3543     int32       ret_value = SUCCEED;
3544     intn        k;                  /* loop index */
3545     intn        i;
3546 
3547 
3548 #ifdef CHK_DEBUG_4
3549     printf("HMCwriteChunk: entered \n");
3550 #endif
3551     /* Check args */
3552     access_rec = HAatom_object(access_id);
3553     if (access_rec == NULL)
3554         HGOTO_ERROR(DFE_ARGS, FAIL);
3555 
3556     if (origin == NULL || datap == NULL)
3557         HGOTO_ERROR(DFE_ARGS, FAIL);
3558 
3559     /* validate file records */
3560     file_rec =  HAatom_object(access_rec->file_id);
3561     if (BADFREC(file_rec))
3562         HGOTO_ERROR(DFE_INTERNAL, FAIL);
3563 
3564     /* can write in this file? */
3565     if (!(file_rec->access & DFACC_WRITE))
3566         HGOTO_ERROR(DFE_DENIED, FAIL);
3567 
3568     /* since this routine can be called by the user,
3569        need to check if this access id is special CHUNKED */
3570     if (access_rec->special == SPECIAL_CHUNKED)
3571       {
3572           /* Set inputs */
3573 #ifdef UNUSED
3574           data     = (uint8 *) datap;
3575 #endif /* UNUSED */
3576           info     = (chunkinfo_t *) (access_rec->special_info);
3577           relative_posn = access_rec->posn;
3578           write_len     = (info->chunk_size * info->nt_size);
3579           bytes_written = 0;
3580           bptr          = datap;
3581 
3582           /* copy origin over to seek chunk indicies
3583              and set position within chunk to beginning of that chunk */
3584           for (i = 0; i < info->ndims; i++)
3585             {
3586               info->seek_chunk_indices[i] = origin[i];
3587               info->seek_pos_chunk[i] = 0;
3588             }
3589 
3590 #ifdef CHK_DEBUG_4
3591           printf(" Seek start(in chunk array):(");
3592           for (i = 0; i < info->ndims; i++)
3593               printf("%d%s", info->seek_chunk_indices[i], i!= info->ndims-1 ? ",":NULL);
3594           printf(")\n");
3595 #endif
3596           /* calculate chunk number from origin */
3597           calculate_chunk_num(&chunk_num, info->ndims, origin,
3598                               info->ddims);
3599 
3600 #ifdef CHK_DEBUG_4
3601     printf("HMCwriteChunk called with chunk %d \n",chunk_num);
3602 #endif
3603           /* find chunk record in TBBT */
3604           if (tbbtdfind(info->chk_tree, &chunk_num, NULL) == NULL)
3605             { /* not in tree */
3606 
3607                 /* so create a new chunk record */
3608                 /* Allocate space for a chunk record */
3609                 if ((chkptr = (CHUNK_REC *) HDmalloc(sizeof(CHUNK_REC))) == NULL)
3610                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3611 
3612                 /* Allocate space for a origin in chunk record */
3613                 if ((chkptr->origin = (int32 *) HDmalloc((size_t)info->ndims*sizeof(int32))) == NULL)
3614                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3615 
3616                 /* allocate space for key */
3617                 if ((chk_key = (int32 *)HDmalloc(sizeof(int32))) == NULL)
3618                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3619 
3620                 /* Initialize chunk record */
3621                 chkptr->chk_tag = DFTAG_NULL;
3622                 chkptr->chk_ref = 0;
3623 #ifdef CHK_DEBUG_4
3624                 printf("HMCwriteChunk: chktpr->chk_tag=%d, ",chkptr->chk_tag);
3625                 printf(" chktpr->chk_ref=%d \n",chkptr->chk_ref);
3626 #endif
3627                 /* Intialize chunk origins */
3628                 for (k = 0; k < info->ndims; k++)
3629                   {
3630                       chkptr->origin[k] = origin[k];
3631 #ifdef CHK_DEBUG_4
3632                       printf("   chktpr->origin[%d]=%d, ",k,chkptr->origin[k]);
3633 #endif
3634                   }
3635 #ifdef CHK_DEBUG_4
3636                 printf("\n");
3637 #endif
3638                 /* set chunk record number to next Vdata record number */
3639                 chkptr->chk_vnum = info->num_recs++;
3640 
3641                 /* set key to chunk number */
3642                 chkptr->chunk_number = *chk_key = chunk_num;
3643 
3644                 /* add to TBBT tree based on chunk number as the key */
3645                 tbbtdins(info->chk_tree, chkptr , chk_key);
3646 
3647 #ifdef UNUSED
3648                 /* assign over new chk */
3649                 chk_rec = chkptr;
3650 #endif /* UNUSED */
3651 
3652                 /* re-intialize ptrs to allow for error-failure check */
3653                 chkptr = NULL;
3654                 chk_key = NULL;
3655             }
3656 #ifdef UNUSED
3657           else /* already in TBBT tree */
3658               chk_rec = (CHUNK_REC *) entry->data; /* get file entry from node */
3659 #endif /* UNUSED */
3660 
3661           /* would be nice to get Chunk record from TBBT based on chunk number
3662              and then get chunk data base on chunk vdata number but
3663              currently the chunk calculations return chunk
3664              numbers and not Vdata record numbers.
3665              This would reduce some overhead in the number of chunks
3666              dealt with in the cache */
3667 
3668           /* get chunk data from cache based on chunk number
3669              chunks in the cache start from 1 not 0 */
3670           if ((chk_data = mcache_get(info->chk_cache, /* cache handle */
3671                                               chunk_num+1,     /* chunk number */
3672                                               0                /* flag: unused */))
3673               == NULL)
3674               HE_REPORT_GOTO("failed to find chunk record", FAIL);
3675 
3676           chk_dptr = chk_data; /* set chunk data ptr */
3677 
3678           /* copy data from users buffer to chunk */
3679           HDmemcpy(chk_dptr, bptr, write_len);
3680 
3681           /* put chunk back to cache and mark it as DIRTY */
3682           if (mcache_put(info->chk_cache, /* cache handle */
3683                          chk_data,        /* whole data chunk */
3684                          MCACHE_DIRTY     /* flag:  DIRTY */)
3685               == FAIL)
3686               HE_REPORT_GOTO("failed to put chunk back in cache", FAIL);
3687 
3688           bytes_written = write_len;
3689 
3690           /*update chunk seek indicies after writing chunk */
3691           update_seek_pos_chunk(bytes_written,info->ndims,info->nt_size,
3692                                 info->seek_pos_chunk,
3693                                 info->ddims);
3694 
3695           /* calculate new read seek postion */
3696           compute_chunk_to_array(info->seek_chunk_indices,info->seek_pos_chunk,
3697                                  info->seek_user_indices,
3698                                  info->ndims,info->ddims);
3699 
3700           compute_array_to_seek(&relative_posn,
3701                                  info->seek_user_indices,
3702                                  info->nt_size,info->ndims,info->ddims);
3703 
3704 #ifdef CHK_DEBUG_4
3705           printf(" new user seek postion in element is %d\n", relative_posn);
3706 #endif
3707           /* update access record with bytes written */
3708           access_rec->posn = relative_posn;
3709 
3710 #ifdef CHK_DEBUG_4
3711           /* for info only */
3712           compute_chunk_to_seek(&relative_posn,info->ndims,info->nt_size,
3713                                info->seek_chunk_indices,
3714                                info->seek_pos_chunk,info->ddims,
3715                                info->chunk_size);
3716 
3717           printf(" new chunk seek postion in element is %d\n", relative_posn);
3718 #endif
3719 
3720           ret_value = bytes_written;
3721       }
3722     else /* not special chunked element */
3723         ret_value = FAIL;
3724 
3725   done:
3726     if(ret_value == FAIL)
3727       { /* Error condition cleanup */
3728           /* check chunk ptrs */
3729           if (chkptr != NULL)
3730             {
3731                 if (chkptr->origin != NULL)
3732                     HDfree(chkptr->origin);
3733                 HDfree(chkptr);
3734             }
3735           if (chk_key != NULL)
3736               HDfree(chk_key);
3737       } /* end if */
3738 
3739     /* Normal function cleanup */
3740 
3741 #ifdef CHK_DEBUG_4
3742     printf("HMCwriteChunk: exited, ret=%d \n",ret_value);
3743 #endif
3744     return ret_value;
3745 }   /* HMCwriteChunk */
3746 
3747 /* ------------------------------- HMCPwrite -------------------------------
3748 NAME
3749    HMCPwrite -- write out some data to a chunked element
3750 
3751 DESCRIPTION
3752    Write out some data to a chunked element.
3753 
3754    Data is obtained from the cache which takes care of obtaining
3755    the proper chunks to write to satisfy the request.
3756 
3757    The chunks are marked as dirty before being returned to the cache.
3758 
3759 RETURNS
3760    The number of bytes written or FAIL on error
3761 AUTHOR
3762    -GeorgeV - 9/3/96
3763 ---------------------------------------------------------------------------*/
3764 int32
HMCPwrite(accrec_t * access_rec,int32 length,const void * datap)3765 HMCPwrite(accrec_t * access_rec, /* IN: access record to mess with */
3766           int32 length,          /* IN: number of bytes to write */
3767           const void * datap      /* IN: buffer for data */)
3768 {
3769     CONSTR(FUNC, "HMCPwrite");    /* for HERROR */
3770     filerec_t   *file_rec = NULL; /* file record */
3771     chunkinfo_t *info     = NULL; /* chunked element information record */
3772 #ifdef UNUSED
3773     CHUNK_REC   *chk_rec  = NULL; /* current chunk */
3774     uint8       *data     = NULL; /* data buffer */
3775     TBBT_NODE   *entry    = NULL; /* node off of  chunk tree */
3776 #endif /* UNUSED */
3777     CHUNK_REC   *chkptr   = NULL; /* Chunk record to inserted in TBBT  */
3778     int32       *chk_key  = NULL; /* Chunk recored key for insertion in TBBT */
3779     const uint8 *bptr     = NULL; /* data buffer pointer */
3780     void        *chk_data = NULL; /* chunk data */
3781     uint8       *chk_dptr = NULL; /* chunk data pointer */
3782     int32       relative_posn;    /* relative position in chunked element */
3783     int32       bytes_written = 0;/* total #bytes written by HMCIwrite */
3784     int32       write_len = 0;    /* next write size */
3785     int32       write_seek = 0;   /* next write seek */
3786     int32       chunk_size = 0;   /* chunk size */
3787     int32       chunk_num = 0;    /* chunk number */
3788     int32       ret_value = SUCCEED;
3789     intn        k;                  /* loop index */
3790 #ifdef CHK_DEBUG_4
3791     intn         i;
3792 #endif
3793 
3794 #ifdef CHK_DEBUG_4
3795     printf("HMCPwrite called with length %d \n",length);
3796 #endif
3797     /* Check args */
3798     if (access_rec == NULL)
3799         HGOTO_ERROR(DFE_ARGS, FAIL);
3800 
3801     /* Set inputs */
3802 #ifdef UNUSED
3803     data     = (uint8 *) datap;
3804 #endif /* UNUSED */
3805     file_rec =  HAatom_object(access_rec->file_id);
3806     info     = (chunkinfo_t *) (access_rec->special_info);
3807     relative_posn = access_rec->posn;
3808     write_len     = length;
3809 
3810     /* validate length and file records */
3811     if (length <= 0)
3812         HGOTO_ERROR(DFE_RANGE, FAIL);
3813     if (BADFREC(file_rec))
3814         HGOTO_ERROR(DFE_INTERNAL, FAIL);
3815 
3816     /* should chunk indicies be updated with relative_posn?
3817        or did last operation update it already */
3818     update_chunk_indicies_seek(access_rec->posn,info->ndims, info->nt_size,
3819                                info->seek_chunk_indices,
3820                                info->seek_pos_chunk,info->ddims);
3821 
3822     bytes_written = 0;
3823     bptr = datap;
3824     while (bytes_written < write_len)
3825       {
3826           /* for debuging */
3827 #ifdef CHK_DEBUG_4
3828           printf("Seek start(in chunk array):(");
3829           for (i = 0; i < info->ndims; i++)
3830               printf("%d%s", info->seek_chunk_indices[i], i!= info->ndims-1 ? ",":NULL);
3831           printf(")\n");
3832           printf(" Seek start(within the chunk):(");
3833           for (i = 0; i < info->ndims; i++)
3834               printf("%d%s", info->seek_pos_chunk[i], i!= info->ndims-1 ? ",":NULL);
3835           printf(")\n");
3836 #endif
3837 
3838           /* calculate chunk to retrieve */
3839           calculate_chunk_num(&chunk_num,info->ndims,info->seek_chunk_indices,
3840                               info->ddims);
3841 
3842           /* calculate contiguous chunk size that we can write to this chunk */
3843           calculate_chunk_for_chunk(&chunk_size,info->ndims,info->nt_size,
3844                                     write_len,bytes_written,
3845                                     info->seek_chunk_indices,
3846                                     info->seek_pos_chunk,info->ddims);
3847 
3848 #ifdef CHK_DEBUG_4
3849           printf("    writing chunk(%d) of %d bytes ->\n", chunk_num, chunk_size);
3850 #endif
3851 
3852           /* find chunk record in TBBT */
3853           if (tbbtdfind(info->chk_tree, &chunk_num, NULL) == NULL)
3854             { /* not in tree */
3855 
3856                 /* so create a new chunk record */
3857                 /* Allocate space for a chunk record */
3858                 if ((chkptr = (CHUNK_REC *) HDmalloc(sizeof(CHUNK_REC))) == NULL)
3859                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3860 
3861                 /* Allocate space for a origin in chunk record */
3862                 if ((chkptr->origin = (int32 *) HDmalloc((size_t)info->ndims*sizeof(int32))) == NULL)
3863                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3864 
3865                 /* allocate space for key */
3866                 if ((chk_key = (int32 *)HDmalloc(sizeof(int32))) == NULL)
3867                     HGOTO_ERROR(DFE_NOSPACE, FAIL);
3868 
3869                 /* Initialize chunk record */
3870                 chkptr->chk_tag = DFTAG_NULL;
3871                 chkptr->chk_ref = 0;
3872 #ifdef CHK_DEBUG_4
3873                 printf(" chktpr->chk_tag=%d, ",chkptr->chk_tag);
3874                 printf(" chktpr->chk_ref=%d, ",chkptr->chk_ref);
3875 #endif
3876                 /* Intialize chunk origins */
3877                 for (k = 0; k < info->ndims; k++)
3878                       chkptr->origin[k] = info->seek_chunk_indices[k];
3879 #ifdef CHK_DEBUG_4
3880                 printf(" chkptr->origin = (");
3881                 for (k = 0; k < info->ndims; k++)
3882                     printf("%d%s", chkptr->origin[k], k!= info->ndims-1 ? ",":NULL);
3883                 printf(")\n");
3884 #endif
3885                 /* set chunk record number to next Vdata record number */
3886                 chkptr->chk_vnum = info->num_recs++;
3887 
3888                 /* set key to chunk number */
3889                 chkptr->chunk_number = *chk_key = chunk_num;
3890 
3891                 /* add to TBBT tree based on chunk number as the key */
3892                 tbbtdins(info->chk_tree, chkptr , chk_key);
3893 
3894 #ifdef UNUSED
3895                 /* assign over new chk */
3896                 chk_rec = chkptr;
3897 #endif /* UNUSED */
3898 
3899                 /* re-intialize ptrs to allow for error-failure check */
3900                 chkptr = NULL;
3901                 chk_key = NULL;
3902             }
3903 #ifdef UNUSED
3904           else /* already in TBBT tree */
3905               chk_rec = (CHUNK_REC *) entry->data; /* get file entry from node */
3906 #endif /* UNUSED */
3907 
3908           /* would be nice to get Chunk record from TBBT based on chunk number
3909              and then get chunk data base on chunk vdata number but
3910              currently the chunk calculations return chunk
3911              numbers and not Vdata record numbers.
3912              This would reduce some overhead in the number of chunks
3913              dealt with in the cache */
3914 #ifdef CHK_DEBUG_4
3915           printf("  getting chunk %d from cache\n",chunk_num);
3916 #endif
3917           /* get chunk data from cache based on chunk number
3918              chunks in the cache start from 1 not 0 */
3919           if ((chk_data = mcache_get(info->chk_cache, /* cache handle */
3920                                               chunk_num+1,     /* chunk number */
3921                                               0                /* flag: unused */))
3922               == NULL)
3923               HE_REPORT_GOTO("failed to find chunk record", FAIL);
3924 
3925           chk_dptr = chk_data; /* set chunk data ptr */
3926 
3927           /* calculate position in chunk */
3928           calculate_seek_in_chunk(&write_seek,info->ndims,info->nt_size,
3929                                   info->seek_pos_chunk,
3930                                   info->ddims);
3931 
3932           chk_dptr += write_seek; /* move to correct position in chunk */
3933 
3934 #ifdef CHK_DEBUG_4
3935           fprintf(stderr,"  write pos in chunk (%d) is %d bytes\n", chunk_num, write_seek);
3936 #endif
3937           /* copy data from users buffer to chunk */
3938           HDmemcpy(chk_dptr, bptr, chunk_size);
3939 
3940 #ifdef CHK_DEBUG_10
3941           printf(" chk_dptr={");
3942           for (i = 0; i < chunk_size; i++)
3943               printf("%d,",(uint8)*((uint8 *)(chk_dptr)+i));
3944           printf("}\n");
3945 #endif
3946           /* put chunk back to cache as DIRTY */
3947           if (mcache_put(info->chk_cache, /* cache handle */
3948                          chk_data,        /* whole data chunk */
3949                          MCACHE_DIRTY     /* flag:  DIRTY */)
3950               == FAIL)
3951               HE_REPORT_GOTO("failed to put chunk back in cache", FAIL);
3952 
3953           /* increment buffer pointer */
3954           bptr += chunk_size;
3955 
3956           /* adjust number of bytes already written */
3957           bytes_written += chunk_size;
3958 
3959 #ifdef CHK_DEBUG_4
3960           printf("     written %d bytes already -> \n", bytes_written);
3961 #endif
3962           /* update relative position i.e. user element seek postion
3963              with chunk size written */
3964           relative_posn += chunk_size;
3965 #ifdef CHK_DEBUG_4
3966           printf("  relative_posn = %d bytes \n", relative_posn);
3967 #endif
3968           /* i.e calculate chunk indices given seek location
3969              this will update the proper arrays in the special info struct */
3970           update_chunk_indicies_seek(relative_posn,info->ndims, info->nt_size,
3971                                      info->seek_chunk_indices,
3972                                      info->seek_pos_chunk,info->ddims);
3973       } /* end while "bytes_written" */
3974 
3975     /* update access record with bytes written */
3976     access_rec->posn += bytes_written;
3977 
3978     ret_value = bytes_written;
3979 
3980   done:
3981     if(ret_value == FAIL)
3982       { /* Error condition cleanup */
3983           /* check chunk ptrs */
3984           if (chkptr != NULL)
3985             {
3986                 if (chkptr->origin != NULL)
3987                     HDfree(chkptr->origin);
3988                 HDfree(chkptr);
3989             }
3990           if (chk_key != NULL)
3991               HDfree(chk_key);
3992       } /* end if */
3993 
3994     /* Normal function cleanup */
3995 
3996 #ifdef CHK_DEBUG_4
3997     printf("HMCPwrite: exited, ret=%d \n",ret_value);
3998 #endif
3999     return ret_value;
4000 }   /* HMCPwrite */
4001 
4002 
4003 /* ---------------------------------------------------------------------
4004 NAME
4005    HMCPcloseAID -- close file but keep AID active
4006 
4007 DESCRIPTION
4008    Close the file currently being pointed to by this AID but
4009    do *NOT* free the AID.
4010 
4011    This will flush the chunk cache and free up the special info struct.
4012 
4013    This is called by Hnextread() which reuses an AID to point to
4014    the 'next' object as requested.  If the current object was an
4015    chunked object, the chunked information needs to be closed before all
4016    reference to it is lost.
4017 
4018    NOTE: Hnextread() is a bad fcn to use since it relies on previous state
4019          information.
4020 
4021 RETURNS
4022    SUCCEED / FAIL
4023 AUTHOR
4024    -GeorgeV - 9/3/96
4025 ---------------------------------------------------------------------------*/
4026 int32
HMCPcloseAID(accrec_t * access_rec)4027 HMCPcloseAID(accrec_t *access_rec /* IN:  access record of file to close */)
4028 {
4029     CONSTR(FUNC, "HMCPcloseAID");    /* for HERROR */
4030     chunkinfo_t *info     = NULL;    /* special information record */
4031     int32       ret_value = SUCCEED;
4032 
4033     /* check args */
4034     info =  (chunkinfo_t *) access_rec->special_info;
4035     if (info == NULL)
4036         HGOTO_ERROR(DFE_ARGS, FAIL);
4037 
4038     /* detach the special information record.
4039        If no more references to that, free the record */
4040     if (--(info->attached) == 0)
4041       {
4042 #ifdef CHK_DEBUG_2
4043     fprintf(stderr,"HMCPcloseAID: info->attached =%d, last one \n", info->attached);
4044 
4045 #endif
4046           if (info->chk_cache != NULL)
4047             {
4048                 /* Sync chunk cache */
4049                 mcache_sync(info->chk_cache);
4050 #ifdef STATISTICS
4051                 /* cache statistics if 'mcache.c' complied with -DSTATISTICS */
4052                 mcache_stat(info->chk_cache);
4053 #endif
4054                 /* close chunk cache */
4055                 mcache_close(info->chk_cache);
4056             } /* cache not empty */
4057 
4058           /* clean up chunk table lists and info record here */
4059           /* Use Vxxx interface to end access to Vdata info */
4060           if (info->aid != FAIL)
4061             {
4062                 if (VSdetach(info->aid) == FAIL)
4063                     HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
4064             }
4065           else
4066               HGOTO_ERROR(DFE_BADAID, FAIL);
4067 
4068           if (Vend(access_rec->file_id) == FAIL)
4069               HGOTO_ERROR(DFE_CANTFLUSH, FAIL);
4070 
4071           /* clean up chunk tree */
4072           tbbtdfree(info->chk_tree, chkdestroynode, chkfreekey);
4073 
4074           /* free up stuff in special info */
4075           if (info->ddims != NULL)
4076               HDfree(info->ddims);
4077           if (info->seek_chunk_indices != NULL)
4078               HDfree(info->seek_chunk_indices);
4079           if (info->seek_pos_chunk != NULL)
4080               HDfree(info->seek_pos_chunk);
4081           if (info->seek_user_indices != NULL)
4082               HDfree(info->seek_user_indices);
4083           if (info->fill_val != NULL)
4084               HDfree(info->fill_val);
4085           if (info->comp_sp_tag_header != NULL)
4086               HDfree(info->comp_sp_tag_header);
4087           if (info->cinfo != NULL)
4088               HDfree(info->cinfo);
4089           if (info->minfo != NULL)
4090               HDfree(info->minfo);
4091           /* finally free up info */
4092           HDfree(info);
4093           access_rec->special_info = NULL;
4094       } /* attached to info */
4095     else
4096       {
4097 #ifdef CHK_DEBUG_2
4098     fprintf(stderr,"HMCPcloseAID: info->attached =%d \n", info->attached);
4099 
4100 #endif
4101       }
4102 
4103   done:
4104     if(ret_value == FAIL)
4105       { /* Error condition cleanup */
4106 
4107       } /* end if */
4108 
4109     /* Normal function cleanup */
4110 
4111     return ret_value;
4112 }   /* HMCPcloseAID */
4113 
4114 /* ----------------------------- HPendaccess -----------------------------
4115 NAME
4116    HMCPendacess -- close a chunk element AID
4117 
4118 DESCRIPTION
4119    Free up all of the space used to store information about a
4120    chunked element. All relevant info will be flushed.
4121    Update proper records i.e. access_rec, file_rec..etc
4122 
4123 RETURNS
4124    SUCCEED / FAIL
4125 AUTHOR
4126    -GeorgeV - 9/3/96
4127 --------------------------------------------------------------------------- */
4128 intn
HMCPendaccess(accrec_t * access_rec)4129 HMCPendaccess(accrec_t * access_rec /* IN:  access record to close */)
4130 {
4131     CONSTR(FUNC, "HMCPendaccess");   /* for HERROR */
4132     filerec_t   *file_rec = NULL;    /* file record */
4133     intn        ret_value = SUCCEED;
4134 
4135     /* validate argument */
4136     if (access_rec == NULL)
4137         HGOTO_ERROR(DFE_ARGS, FAIL);
4138 
4139     /* get file rec and special info */
4140     file_rec = HAatom_object(access_rec->file_id);
4141     if (BADFREC(file_rec))
4142         HGOTO_ERROR(DFE_ARGS, FAIL);
4143 
4144     /* detach the special information record.
4145        If no more references to that, free the record */
4146     if (HMCPcloseAID(access_rec) == FAIL)
4147         HGOTO_ERROR(DFE_CANTCLOSE, FAIL);
4148 
4149     /* update file and access records */
4150     if (HTPendaccess(access_rec->ddid) == FAIL)
4151         HGOTO_ERROR(DFE_CANTENDACCESS, FAIL);
4152 
4153     /* detach from the file */
4154     file_rec->attach--;
4155 
4156     /* free the access record */
4157     HIrelease_accrec_node(access_rec);
4158 
4159   done:
4160     if(ret_value == FAIL)
4161       { /* Error condition cleanup */
4162         if(access_rec!=NULL)
4163             HIrelease_accrec_node(access_rec);
4164       } /* end if */
4165 
4166     /* Normal function cleanup */
4167     return ret_value;
4168 }   /* HMCPendaccess */
4169 
4170 /* ------------------------------- HMCPinfo --------------------------------
4171 NAME
4172    HMCPinfo -- return info about a chunked element
4173 
4174 DESCRIPTION
4175    Return information about the given chunked element.
4176    'info_chunk' is assumed to be non-NULL.
4177 
4178 RETURNS
4179    SUCCEED / FAIL
4180 AUTHOR
4181    -GeorgeV - 9/3/96
4182 --------------------------------------------------------------------------- */
4183 int32
HMCPinfo(accrec_t * access_rec,sp_info_block_t * info_chunk)4184 HMCPinfo(accrec_t *access_rec,       /* IN: access record of access elemement */
4185          sp_info_block_t *info_chunk /* OUT: information about the special element */)
4186 {
4187     CONSTR(FUNC, "HMCPinfo");       /* for HERROR */
4188     chunkinfo_t *info     = NULL;   /* special information record */
4189     int32       ret_value = SUCCEED;
4190     intn        i;                  /* loop variable */
4191 
4192     /* Check args */
4193     if (access_rec == NULL)
4194         HGOTO_ERROR(DFE_ARGS, FAIL);
4195 
4196     /* validate access record */
4197     if (access_rec->special != SPECIAL_CHUNKED)
4198         HGOTO_ERROR(DFE_INTERNAL, FAIL);
4199 
4200     /* fill in the info_chunk */
4201     info =  (chunkinfo_t *) access_rec->special_info;
4202     info_chunk->key        = SPECIAL_CHUNKED;
4203     info_chunk->chunk_size = (info->chunk_size * info->nt_size); /* phsyical size */
4204     info_chunk->ndims      = info->ndims;
4205     if ((info->flag & 0xff) == SPECIAL_COMP) /* only using 8bits for now */
4206       {
4207           info_chunk->comp_type  = (int32)info->comp_type;
4208           info_chunk->model_type = (int32)info->model_type;
4209       }
4210     else
4211       {
4212           info_chunk->comp_type  = COMP_CODE_NONE;
4213           info_chunk->model_type = 0;
4214       }
4215 
4216     /* allocate space for chunk lengths */
4217     if (( info_chunk->cdims = (int32 *) HDmalloc((size_t)info->ndims*sizeof(int32)))==NULL)
4218         HGOTO_ERROR(DFE_NOSPACE, FAIL);
4219 
4220     /* copy info over */
4221     for (i = 0; i < info->ndims; i++)
4222       {
4223           info_chunk->cdims[i] = info->ddims[i].chunk_length;
4224       }
4225 
4226   done:
4227     if(ret_value == FAIL)
4228       { /* Error condition cleanup */
4229           if (info_chunk->cdims != NULL)
4230               HDfree(info_chunk->cdims);
4231       } /* end if */
4232 
4233     /* Normal function cleanup */
4234 
4235     return ret_value;
4236 }   /* HMCPinfo */
4237 
4238 /* ------------------------------ HMCPinquire -----------------------------
4239 NAME
4240    HMCPinquire -- Hinquire for chunked elements
4241 
4242 DESCRIPTION
4243    Return interesting information about a chunked element.
4244    NULL can be passed for any of the OUT parameters if their
4245    value is not needed.
4246 
4247 RETURNS
4248    SUCCEED/FAIL
4249 AUTHOR
4250    -GeorgeV - 9/3/96
4251 --------------------------------------------------------------------------- */
4252 int32
HMCPinquire(accrec_t * access_rec,int32 * pfile_id,uint16 * ptag,uint16 * pref,int32 * plength,int32 * poffset,int32 * pposn,int16 * paccess,int16 * pspecial)4253 HMCPinquire(accrec_t *access_rec,  /* IN:  access record to return info about */
4254             int32 *pfile_id,       /* OUT: file ID; */
4255             uint16 *ptag,          /* OUT: tag of info record; */
4256             uint16 *pref,          /* OUT: ref of info record; */
4257             int32 *plength,        /* OUT: length of element; */
4258             int32 *poffset,        /* OUT: offset of element -- meaningless */
4259             int32 *pposn,          /* OUT: current position in element; */
4260             int16 *paccess,        /* OUT: access mode; */
4261             int16 *pspecial        /* OUT: special code; */)
4262 {
4263     CONSTR(FUNC, "HMCPinquire");    /* for HERROR */
4264     uint16      data_tag, data_ref; /* Tag/ref of the data in the file */
4265     chunkinfo_t *info = NULL;       /* special information record */
4266     int32       ret_value = SUCCEED;
4267 
4268     /* Check args */
4269     if (access_rec == NULL)
4270         HGOTO_ERROR(DFE_ARGS, FAIL);
4271 
4272     /* get special info */
4273     info =   (chunkinfo_t *) access_rec->special_info;
4274 
4275     /* get latest info for the dataset */
4276     if(HTPinquire(access_rec->ddid,&data_tag,&data_ref,NULL,NULL)==FAIL)
4277         HGOTO_ERROR(DFE_INTERNAL, FAIL);
4278 
4279     /* fill in the variables if they are present */
4280     if (pfile_id)
4281         *pfile_id = access_rec->file_id;
4282     if (ptag)
4283         *ptag = data_tag;
4284     if (pref)
4285         *pref = data_ref;
4286     if (plength)
4287         *plength = (info->length * info->nt_size);
4288     if (poffset)
4289         *poffset = 0;   /* meaningless */
4290     if (pposn)
4291         *pposn = access_rec->posn;
4292     if (paccess)
4293         *paccess = (int16)access_rec->access;
4294     if (pspecial)
4295         *pspecial = (int16)access_rec->special;
4296 
4297   done:
4298     if(ret_value == FAIL)
4299       { /* Error condition cleanup */
4300 
4301       } /* end if */
4302 
4303     /* Normal function cleanup */
4304     return ret_value;
4305 }   /* HMCPinquire */
4306 
4307 /* -------------------------------------------------------------------------
4308 NAME
4309    HMCPgetnumrecs -- get the number of records in a chunked element
4310 DESCRIPTION
4311    Retrieves the number of records in a chunked element.
4312    This function was originally added for SDcheckempty/HDcheckempty to
4313    determine whether a chunked SDS has been written with data.
4314 RETURNS
4315    SUCCEED/FAIL - FAIL when num_recs is NULL
4316 AUTHOR
4317    bmribler - 10/3/2004
4318 ---------------------------------------------------------------------------*/
4319 int32
HMCPgetnumrecs(accrec_t * access_rec,int32 * num_recs)4320 HMCPgetnumrecs(accrec_t* access_rec,	/* access record */
4321                int32 *num_recs		/* OUT: length of the chunked elt */)
4322 {
4323     CONSTR(FUNC, "HMCPgetnumrecs");	/* for HGOTO_ERROR */
4324     chunkinfo_t *chunk_info = NULL;	/* chunked element information record */
4325     int32       ret_value = SUCCEED;
4326 
4327     /* Check args */
4328     if (access_rec == NULL)
4329         HGOTO_ERROR(DFE_ARGS, FAIL);
4330 
4331     /* get the special info from the given record */
4332     chunk_info = (chunkinfo_t *) access_rec->special_info;
4333     if (chunk_info == NULL) HGOTO_ERROR(DFE_ARGS, FAIL);
4334 
4335     if (num_recs)
4336         *num_recs = chunk_info->num_recs;
4337     else
4338 	ret_value = FAIL;
4339 
4340   done:
4341     if(ret_value == FAIL)
4342       { /* Error condition cleanup */
4343 
4344       } /* end if */
4345 
4346     /* Normal function cleanup */
4347     return ret_value;
4348 }   /* HMCPgetnumrecs */
4349 
4350