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